flowchart LR
subgraph POR["por vértice"]
P["posição<br/>onde o ponto está"]
N["normal<br/>como a luz responde ali"]
U["coordenada de textura<br/>que pedaço da imagem cai ali"]
end
F["faces<br/>que vértices formam cada triângulo"]
POR --> M["a peça desenhada"]
F --> M
P -.->|"errada"| S1["silhueta MUDA<br/>o defeito se enxerga"]
N -.->|"errada"| S2["silhueta intacta<br/>a peça escurece"]
U -.->|"errada"| S3["silhueta intacta<br/>o desenho estica"]
F -.->|"invertida"| S4["silhueta intacta<br/>buraco visível de um ângulo só"]
1 Técnicas de modelagem de ambientes virtuais
A oficina ganha forma, e a peça mais cara que ela recebe é uma caixa que ninguém enxerga.
Seis coisas que uma fotografia da oficina não prova. Que nenhuma face está com a normal invertida. Que a densidade de cada malha tem razão. Que os materiais são compartilhados entre peças de mesma superfície. Que toda peça manipulável tem volume de contato. Que cada folga carrega a justificativa ao lado do número. E que nenhum par de caixas invisíveis se sobrepõe com as peças em repouso.
Abra a oficina do capítulo anterior e olhe para a engrenagem grande. Ela tem catorze dentes agora. O flanco de cada dente é chapado. O vale entre dois deles é fundo. A peça ocupa a tela de um jeito que a caixa cinzenta não ocupava. Alguém trabalhou ali, e dá para ver.
Agora olhe em volta dela. Não há nada para ver. A engrenagem carrega uma caixa invisível de 19,5 por 5,6 por 19,6 centímetros. Ela envolve a silhueta com dois centímetros de sobra em cada direção. Essa caixa levou mais tempo para ser decidida do que os catorze dentes. Ela não aparece em captura de tela, não muda um pixel e não produz sintoma algum enquanto ninguém tentar apanhar a peça.
O senso comum sobre modelar um ambiente virtual diz que o trabalho é fazer as coisas parecerem certas. Essa é metade do trabalho, e é a metade que se confere olhando. A outra metade decide o que acontece quando alguém encosta. Ela não tem imagem, e por isso se confere de outro jeito.
Há um agravante, e ele muda o método de conferência daqui em diante. A metade visível engana. Das quatro listas de números que formam uma peça, uma errada muda a silhueta e três a conservam intacta. Nenhuma das três produz erro, aviso ou mensagem.
1.1 Quatro listas, e três erram em silêncio
Pedir uma caixa pronta à biblioteca devolve uma caixa e esconde as quatro decisões que moram dentro dela.
Uma malha é um feixe de listas paralelas, com uma entrada por vértice, mais uma lista que enumera triângulos apontando para essas entradas. Cada lista responde a uma pergunta diferente sobre o mesmo ponto. Onde ele está. Como a luz o encontra. Que pedaço de imagem cai sobre ele. As três perguntas não têm relação umas com as outras. Responder bem a uma delas não ajuda em nada nas outras duas.
Uma malha é um conjunto de listas paralelas, com uma entrada por vértice, mais uma lista de faces que liga esses vértices.
Por vértice guardam-se três coisas: a posição, que decide onde o ponto está no espaço; a normal, que decide como a luz responde ali; e o par de coordenadas de textura, que decide qual pedaço de uma imagem cai sobre aquele ponto. A lista de faces enumera triângulos por índice de vértice.
A forma que se vê é o resultado das quatro listas juntas, e o sintoma de erro é desigual entre elas. Errar as posições muda a silhueta, e isso se enxerga. Errar qualquer uma das outras três conserva a silhueta exata e muda o que aparece dentro dela.
O menor exemplo concreto é uma única chamada que registra um vértice. Ela recebe oito números: três de posição, três de direção e dois de coordenada de imagem. Os oito descrevem o mesmo ponto, e nenhum deles pode ser deduzido dos outros.
Repare no que a assinatura obriga. Quem chama essa função precisa ter opinião sobre oito números, um por um, no instante em que o ponto nasce. A caixa pedida pronta dispensa as oito opiniões e devolve uma caixa correta. Por dispensá-las, ela não ensina a diagnosticar coisa alguma.
A definição não exige coisas que muita gente lê nela. Triângulos de tamanhos parecidos, vértices compartilhados entre faces vizinhas, coordenadas de imagem cobrindo a superfície sem sobreposição: nada disso está ali. Malhas úteis violam as três com frequência.
1.1.1 Uma decide se a face existe; a outra decide como ela responde
Alguém escreve a casca lateral de uma engrenagem e a peça sai escura. Não preta, não sumida: escura, sem leitura, com o contorno dos catorze dentes recortado com perfeição contra o fundo. O primeiro palpite é a iluminação, e ele é razoável. A superfície é metálica, metal depende do que existe em volta para refletir, e a cena tem uma fonte de luz só. A tarde vai embora em ajustes de intensidade, de posição e de cor da fonte.
O defeito estava na direção que cada vértice declara como “para fora”. Ela foi calculada com dois fatores em ordem trocada e aponta para dentro da peça. A iluminação consulta essa direção para decidir o brilho. Encontra uma face que lhe dá as costas. E faz exatamente o que lhe foi pedido: escurece. A silhueta ficou perfeita a tarde inteira, porque a direção que decide a luz não participa do recorte da peça contra o fundo.
A orientação de uma face é o sentido em que ela enumera os seus vértices. A biblioteca desenha a face cuja borda percorre o sentido anti-horário quando vista de fora, e omite a face percorrida no sentido contrário — sem erro, aviso ou mensagem.
A normal de um vértice é a direção que o programa declara como “para fora” naquele ponto, e é ela que a iluminação consulta para decidir o brilho da superfície.
Um vértice usado por várias faces carrega uma normal só, que serve a todas elas. Compartilhar o ponto entre faces de orientações diferentes suaviza o canto entre elas; duplicar o ponto, com uma cópia por face, conserva a aresta viva ao preço de mais vértices na malha.
As duas erram de maneiras que se parecem na descrição e são opostas no efeito. A orientação errada produz ausência: a face deixa de ser desenhada, e por ali se vê o interior da peça. Como a face oposta continua sendo desenhada, o buraco aparece de um lado e não do outro. A engrenagem some pela metade quando a câmera passa por cima e volta ao normal quando ela desce. O defeito parece intermitente, e trinta linhas plausíveis entram na lista de suspeitos.
A normal errada produz escuridão, com a face inteira no lugar, com a mesma área e o mesmo recorte. Que sinal separa esse caso de um problema de iluminação? Gire a peça devagar contra a fonte de luz e observe a lateral. A normal invertida escurece justamente quando a face encara a fonte, que é o contrário do que qualquer superfície faz. O teste custa dez segundos e elimina a tarde descrita ali em cima.
a normal da casca lateral, em src/bancada/content/malha.ts
// Normal para fora: o produto vetorial do eixo vertical pela direção da
// aresta. Na ordem inversa ela apontaria para dentro da peça, e a luz
// acertaria a face pelo lado errado — a peça fica escura e ninguém acha o
// motivo, porque a silhueta continua perfeita.
const nx: number = (q.z - p.z) / comprimento;
const nz: number = -(q.x - p.x) / comprimento;Duas linhas de conta e quatro de comentário. A desproporção é o ponto. Na versão certa e na errada, as duas linhas ficam idênticas, a menos da ordem de dois fatores. Nada no código torna uma delas mais plausível que a outra. O comentário é o que sobrevive ao esquecimento de quem escreveu.
1.1.2 O vértice que se duplica de propósito
Por que uma malha gastaria vértices a mais de propósito? A engrenagem grande sai com 338 vértices para 224 triângulos, quando compartilhar pontos entre faces vizinhas devolveria bem menos. Parece desperdício de memória e é escolha de aparência.
O que se compra com os vértices a mais é a aresta viva. Um vértice compartilhado por duas faces carrega uma normal só, e essa normal única acaba sendo alguma média entre as duas orientações. A luz então varia suavemente ao atravessar o canto, e o canto deixa de existir para o olho.
Numa esfera isso é exatamente o que se quer. O canto entre duas faces vizinhas é artefato da discretização, e suavizá-lo aproxima a peça da superfície que ela representa. Num dente de engrenagem acontece o oposto. O flanco encontra a crista num ângulo que existe na peça de verdade, e arredondá-lo transforma uma peça mecânica em brinquedo.
A conta dos 338 fecha à mão, e fazê-la uma vez vale mais do que aceitar o número. São 57 vértices na face de cima (o centro mais um por ponto do perfil) e outros 57 na face de baixo. Na casca lateral vão 224, quatro por aresta, nenhum compartilhado com a vizinha. O eixo percorre o mesmo caminho e sai com 74 vértices para 48 triângulos.
Antes de seguir. Pegue um objeto do seu projeto e olhe cada canto dele. Esse ângulo existe no objeto de verdade, ou é resíduo de você ter aproximado uma curva por pedaços retos? A resposta decide se o vértice ali se compartilha ou se duplica. Ela não depende de uma linha de código sequer.
1.2 Catorze grupos de quatro pontos, e nada mais
Uma engrenagem é um contorno plano puxado para cima. A frase parece simplificação didática e é a arquitetura literal do arquivo que constrói a peça.
O contorno de um dente tem quatro pontos, e cada um é uma decisão. Sobe à crista. Atravessa a crista. Desce à raiz. Atravessa o vale. Os ângulos em que essas quatro coisas acontecem separam um dente que parece dente de um serrilhado qualquer.
Geometria paramétrica é a forma descrita por uma função dos seus parâmetros e construída pela execução dessa função.
A construção por perfil e extrusão tem duas partes de papéis desiguais. O perfil é um contorno plano, dado como sequência de pontos, e é nele que mora toda a decisão de forma. A extrusão levanta o contorno numa espessura, fecha as duas tampas e costura a casca lateral, e é a mesma rotina para qualquer perfil.
Trocar o perfil troca a peça. Os parâmetros do perfil — quantos elementos, com que raios — são o botão de densidade da malha: cada elemento acrescenta um número fixo de triângulos ao resultado, e esse número é pago em todo quadro.
A engrenagem grande tem catorze dentes, raio de raiz de sessenta e oito milímetros e raio de crista de setenta e oito. O contorno resultante tem 56 pontos, quatro por dente. A rotina de extrusão recebe esses 56 pontos e devolve a peça inteira, sem saber que aquilo era uma engrenagem. A definição não crava número algum, e nem exige perfil fechado, espessura constante ou casca perpendicular às tampas.
A desigualdade entre as duas partes é de onde vem a economia toda. O perfil é curto, específico e muda a cada peça. A extrusão é longa, genérica e nunca muda. Escrever uma engrenagem passa a ser escrever catorze grupos de quatro pontos. Fechar tampas, costurar a casca lateral e distribuir coordenadas já está feito e conferido.
Essa divisão também decide onde procurar quando algo sai errado. Peça com silhueta estranha é problema de perfil, e o perfil cabe numa dúzia de linhas legíveis. Peça com silhueta certa e superfície estranha é problema de extrusão — e se a extrusão estivesse errada, todas as peças estariam.
A prova de que a autoria mora no contorno é trocar o contorno e ver o que sobra de pé. O eixo da oficina usa a mesma rotina de extrusão, com um perfil regular de doze lados no lugar dos catorze dentes. Sai um cilindro, e nenhuma linha da rotina precisou ser tocada. À distância de trabalho o cilindro convence; de perto, a faceta aparece, e cada lado responde à luz com um valor só.
Essa faceta é evidência visível de uma decisão tomada uma seção atrás. A normal foi decidida por face, e não interpolada entre vizinhas. Conte os lados visíveis do eixo numa captura ampliada. Se der doze, a decisão está de pé. Se a superfície aparecer contínua, alguém pediu à biblioteca normais suaves — e essa escolha vai valer também para os dentes da engrenagem. É por isso que a rotina de extrusão não tem opinião sobre suavização. Uma rotina que decidisse por todas acoplaria a aparência do eixo à aparência da engrenagem.
A quarta lista de uma malha é a que menos sentido faz escrever agora. As superfícies deste ponto do percurso são de cor lisa. Nenhuma imagem cai sobre peça alguma, e as coordenadas de textura escritas aqui não têm consumidor.
a coordenada que acompanha o perímetro, em src/bancada/content/malha.ts
// Casca lateral. Cada aresta do perfil vira um retângulo com normal própria,
// perpendicular a ela: é isso que dá o dente com flanco chapado em vez de
// ombro arredondado. A coordenada horizontal da textura acompanha o perímetro
// percorrido, e a vertical vai da base ao topo.
let percorrido: number = 0;A coordenada horizontal acompanha o perímetro percorrido e a vertical vai da base ao topo. É a distribuição natural para uma casca lateral, e escrevê-la agora custa uma variável acumuladora e o cuidado de fazê-la avançar junto com o perímetro. Adiar custa mais, e o custo é de diagnóstico. A distribuição errada não produz sintoma enquanto não houver imagem. No dia em que houver, o sintoma engana. O desenho aparece esticado numa face e comprimido na vizinha. Quem vê isso procura o defeito na imagem, que é onde ele se manifesta. O defeito está na geometria, escrita semanas antes por alguém que talvez nem esteja mais no mesmo arquivo.
Há um caso em que adiar é a decisão certa. Peça que nunca vai receber imagem — um volume auxiliar, um marcador de depuração, uma primitiva de teste — não precisa de coordenada nenhuma. O critério é estreito: escreve-se a coordenada de quem vai ser vestido.
1.3 O que a cena cobra, e o que ela declara
A conta de um quadro tem duas metades, e a segunda não é feita de geometria.
Cada quadro é um envelope de onze milissegundos, e o que não couber nele não fica para depois: some. O envelope foi declarado no capítulo anterior sobre uma cena de caixas cinzentas, quando havia folga a página inteira e nada de pesado a que atribuir culpa. Agora ele tem contra o que ser gasto.
1.3.1 Catorze dentes contra vinte e quatro
Cada dente acrescenta dezesseis triângulos à malha final. São quatro pontos de contorno, cada um virando uma aresta da casca lateral, cada aresta virando dois triângulos, mais o que as duas tampas somam. Passar de catorze para vinte e quatro dentes acrescenta cento e sessenta triângulos a uma peça só. A conta se repete em toda peça que receber o mesmo tratamento.
Veja o outro lado da conta, que é o olho. A engrenagem grande mede quinze centímetros e é vista a cerca de meio metro. A essa distância, a diferença angular entre um dente e o vizinho está abaixo do que a vista separa numa peça em movimento. Os vinte e quatro dentes chegam à placa de vídeo. São desenhados com o mesmo cuidado que os catorze. E não chegam a ninguém.
Repare no que essa frase não afirma. Ela não diz que mais triângulos sejam sempre desperdício. Diz que existe uma resolução acima da qual o acréscimo não chega ao olho. Essa resolução depende de duas coisas concretas: o tamanho da peça e a distância de onde ela é olhada. Mude uma das duas e o número muda junto. Uma peça que quem usa aproxima do rosto a vinte centímetros pede mais dentes do que a mesma peça vista de meio metro.
O erro comum aqui é escolher uma vez e nunca mais revisar. O número foi digitado num dia em que a cena tinha outro tamanho e outra câmera. E continua lá, com a autoridade de quem já estava no arquivo antes de você chegar.
1.3.2 Quatrocentos e quarenta triângulos, e o que eles não são
As cinco peças da oficina somam 440 triângulos. São 224 na engrenagem grande, 144 na pequena, 48 no eixo e 12 em cada uma das duas primitivas que continuam sendo primitivas. Esse número é um censo, e a palavra faz diferença. Ele conta o que a cena tem, e sai do inventário que o próprio código imprime ao abrir a página.
Ele não é um teto, não é uma meta, não é promessa de desempenho e não descreve capacidade de máquina nenhuma. O que a plataforma aguenta continua sem medição neste percurso, e escrever aqui um número de orçamento seria inventá-lo. A distinção entre as duas coisas é fácil de enunciar. “A oficina tem 440 triângulos” se confere lendo uma lista. “A máquina aguenta tantos triângulos” só se sabe medindo a máquina com uma cena que a force.
Um censo tem um uso que um teto não teria, e é para isso que ele está escrito. Ele é linha de base. Adiante entram modelos vindos de fora, com contagem decidida por outra pessoa para outro propósito. A única forma de saber o que eles acrescentaram é ter a contagem anterior anotada. Anotar 440 hoje custa uma linha impressa. Reconstruir o estado antigo daqui a duas semanas custa bem mais, e ninguém reconstrói estado antigo por curiosidade.
1.3.3 O triângulo é barato; a troca é cara
A segunda metade da conta costuma dominar a primeira. Desenhar mil triângulos com um material só custa bem menos do que desenhar mil triângulos divididos em dez materiais.
A razão está no que um material é para a placa de vídeo: um programa compilado, com os seus parâmetros. Trocar de material entre dois lotes de triângulos significa trocar o programa em execução. A troca tem custo fixo, independente de quantos triângulos venham depois dela. Um lote grande dilui o custo fixo; muitos lotes pequenos o multiplicam pelo número de trocas que a cena exige em cada quadro.
flowchart LR
Q["o quadro<br/>envelope de onze milissegundos"]
Q --> T["primeira metade<br/>triângulos desenhados"]
Q --> E["segunda metade<br/>trocas de estado por material"]
T --> T1["440 triângulos na oficina<br/>224 na engrenagem grande"]
T --> T2["cada dente acrescenta<br/>dezesseis triângulos"]
E --> E1["material é programa compilado<br/>trocar custa por troca, não por triângulo"]
E --> E2["quatro superfícies para cinco peças<br/>as duas engrenagens dividem a mesma instância"]
T1 --> C["censo da cena construída<br/>linha de base para comparar depois"]
E2 --> C
Disso decorre um hábito que vale mais do que qualquer otimização posterior: contenha o catálogo. A oficina inteira tem quatro superfícies para cinco peças, e a contenção foi decisão de projeto, não consequência de pressa.
os dois tetos declarados, em src/bancada/core/orcamento.ts
Os dois tetos do capítulo anterior continuam os mesmos, e agora existe conteúdo que os consome. Eu orço pelo mais apertado dos dois — o do visor —, mesmo escrevendo a cena na máquina de mesa. O motivo é a assimetria do preço. Folga desperdiçada na janela custa um pouco de aparência; envelope estourado no visor custa mal-estar em quem está com o aparelho no rosto. O teto apertado governa as três decisões desta página. Catorze dentes em vez de vinte e quatro. Quatro superfícies em vez de nove. E a caixa no lugar da malha no teste de contato. Nenhuma delas é heroica sozinha.
1.3.4 Declara-se a matéria; a luz decide o resto
Como se diz a uma biblioteca gráfica que uma peça é de latão? Há dois caminhos. Um descreve o resultado — “um cinza brilhante” — e é direto, previsível e o que quase todo primeiro exemplo faz. O outro descreve a matéria — “metálica, pouco rugosa” — e aceita que a cor final dependa de onde a peça está.
Uma superfície se declara por propriedades do material — quanto ele é metálico e quanto é rugoso —, e a aparência final é o que a luz da cena produz sobre essas propriedades.
Daí decorre uma dependência que a declaração sozinha esconde: a superfície metálica devolve ao olho o que existe em volta para refletir, e uma cena com pouca luz ao redor a deixa escura e sem leitura, mesmo com a declaração intacta.
Uma superfície declarada é uma instância, e a mesma instância pode ser apontada por quantas peças a usem. Duas instâncias idênticas em valor permanecem distintas para a placa de vídeo, que trata cada uma como um programa próprio e troca de estado uma vez por cada.
O menor exemplo concreto é uma peça que atravessa dois ambientes. Ela é vista primeiro na sala do computador de mesa, sob a iluminação sintética que a cena declara. Depois é vista no regime que preserva o mundo físico atrás dela, onde a luz que existe é a da sala de verdade. A peça descrita por matéria muda nos dois lugares e continua coerente nos dois. A peça descrita por cor fica idêntica nos dois, e é essa identidade que a denuncia. No segundo ambiente ela parece recortada e colada — a única coisa em cena que não respondeu à luz que todas as outras responderam.
A definição não promete realismo, e não convém lê-la como se prometesse. Um modelo com dois parâmetros não descreve tinta descascada, poeira acumulada, nem a diferença entre latão novo e latão que passou trinta anos numa oficina. Esses acabamentos entram por imagem, que é assunto de outro momento do percurso.
A dependência declarada pega quase todo mundo uma vez. Numa cena com uma única fonte de luz e nada em volta, o ambiente refletido é quase nada. A peça metálica fica escura e chapada. Quem vê isso pela primeira vez culpa o material, e a conclusão parece razoável: a peça está errada, o material é a declaração dela, logo o material está errado. A busca começa nos dois parâmetros, e nenhum ajuste neles resolve, porque os dois estão corretos.
O problema é da cena. Uma superfície que devolve o que existe em volta precisa que exista alguma coisa em volta. A correção é acrescentar luz ambiente, uma segunda fonte, ou um mapa de entorno, e nenhuma das três mora no arquivo que descreve a peça. Compare com a normal invertida da primeira seção. Lá a peça estava errada e a suspeita caía na luz. Aqui a luz está incompleta e a suspeita cai na peça.
Que sinal separa os dois casos? Ponha na cena, ao lado da peça suspeita, uma superfície nada metálica e bem rugosa. Se ela também estiver escura, o problema é da iluminação da cena. Se ela aparecer normalmente e só a metálica ficar escura, falta entorno para refletir. O teste é conclusivo nos dois sentidos, e conclusão nos dois sentidos é coisa rara.
Uma escolha de material costuma ser registrada em uma coluna só: o nome da superfície e como ela deve parecer. Falta a segunda coluna, e sem ela a escolha é palpite bem-intencionado.
a descrição com as duas colunas, em src/bancada/content/materiais.ts
O que importa ali é o último campo: o que a superfície cobra em tempo real, escrito em uma frase, ao lado do que ela entrega. Um tipo que exige as duas colunas cobra duas opiniões de quem acrescenta uma superfície. Uma sobre a aparência, outra sobre o consumo, as duas no mesmo instante.
O catálogo da oficina tem quatro superfícies, e uma delas é dividida por duas peças. As duas engrenagens dividem o mesmo latão, e dividem a mesma instância: a mesma referência, criada uma vez e apontada duas vezes. Criar duas instâncias com valores idênticos seria mais natural de escrever. E produziria dois programas distintos para a placa, com duas trocas de estado por quadro no lugar de uma. A placa não compara valores para descobrir que dois programas fazem a mesma coisa. Ela recebe dois identificadores diferentes e trata cada um como uma coisa diferente. Comportamento correto dela, resultado errado para quem escreveu a cena.
Num catálogo de quatro, essa diferença é invisível em qualquer medição que se faça hoje. O que está sendo formado aqui é o hábito. Ele cobra num catálogo de quarenta, com a cena inteira já escrita sobre a forma errada.
1.4 Autorar, pedir pronto, ou trazer de fora
Uma forma chega à cena por três caminhos, e os três convivem no mesmo projeto sem contradição alguma. Escrevê-la em código. Pedi-la à biblioteca. Trazê-la de uma ferramenta de autoria.
A cena do capítulo anterior sobe primeiro, com a estrutura e o parentesco que ela já tinha. A forma entra depois, sobre a árvore pronta. A operação que veste a cena percorre os nós que a montagem criou e substitui o conteúdo de cada um. Nenhum nó é criado, nenhum é removido, e nenhum troca de pai. A árvore que existe ao final tem exatamente a mesma forma da que existia no início.
Essa restrição mantém cada assunto num lugar só. A estrutura pertence ao capítulo da estrutura; a forma pertence a este. Escrever a geometria dentro da rotina que monta a cena economizaria um arquivo. E fundiria os dois assuntos num só, sem que nada no resultado denunciasse a fusão. Há um ganho concreto além da arrumação: o estado anterior continua exibível. Exibi-lo ao lado da versão vestida separa duas perguntas que a versão vestida embaralha — se as peças estão nos lugares certos, e se elas parecem certas.
A operação também trata o caso em que o nó recebido não é o que ela esperava. Ela interrompe a execução e nomeia a peça, em vez de ignorar o nó e seguir adiante. Aceitar em silêncio deixaria a peça na cena com a forma provisória. E a diferença entre a caixa por decisão e a caixa por troca falhada desapareceria da tela.
1.4.1 Nem toda peça pede malha autorada
Duas das cinco peças recusam a geometria escrita à mão, e a recusa está registrada no arquivo. O corpo do mecanismo é uma caixa e a tampa é uma placa, as duas pedidas prontas à biblioteca. Escrever à mão a malha de um paralelepípedo é um exercício de oito vértices e doze triângulos. O resultado é idêntico ao que a biblioteca já entregava, pelo mesmo custo em quadro. O único ganho é poder dizer que foi escrito à mão.
A fronteira defensável cabe numa frase: a geometria autorada vai onde a forma carrega significado. O dente que engrena carrega significado, porque o ângulo do flanco decide se a peça parece mecânica ou parece serrilhada. A faceta do eixo carrega significado, porque denuncia como as normais foram decididas. Um paralelepípedo não carrega significado além de ser um paralelepípedo.
Essa fronteira tem um lado que a defende contra o excesso oposto. Uma cena inteira feita de primitivas foi recebida pronta, e ninguém a compôs. Ela pode estar correta em estrutura, em custo e em material, e não conter uma única decisão de forma tomada por quem a montou. O critério que separa os dois excessos se aplica peça a peça. Alguma coisa desta forma comunica alguma coisa sobre o objeto? Se comunica, a forma é conteúdo e se autora. Se a peça é caixa porque o objeto é caixa, pedir a caixa é a decisão certa. Ela não precisa de defesa mais elaborada do que essa.
Justificativa se escreve no instante em que a decisão é tomada. Passadas duas semanas, o código deixa de distinguir a peça primitiva por escolha da peça primitiva porque ninguém chegou nela. As duas ficam idênticas, e a diferença sobrevive só na memória de quem estava presente.
Trocar a malha de um nó tem ainda um passo que não aparece na descrição da troca. A malha anterior ocupa memória na placa de vídeo, e essa memória não é recuperada pelo mesmo mecanismo que recupera a memória comum do programa. A rotina de vestir libera a malha antiga antes de instalar a nova. Numa troca isso não produz diferença observável, o que torna a omissão fácil de cometer e difícil de perceber. O sintoma aparece em ambiente que recarrega conteúdo várias vezes na mesma sessão. A memória de vídeo se esgota, o navegador perde o contexto de desenho, a tela fica preta. Nenhuma mensagem acompanha a perda. Ninguém procura a causa na enésima execução de uma rotina que funcionou nas anteriores.
1.4.2 Três defeitos que a ferramenta não mostra
Nada obriga a escrever geometria em código. Existem ferramentas de autoria feitas para isso, com décadas de refinamento. É com elas que a maior parte do conteúdo tridimensional do mundo é produzida. Uma malha exportada de uma delas costuma chegar ao ambiente em execução com três problemas, e os três são invisíveis do lado de lá.
O primeiro é a contagem de triângulos. Ferramentas de autoria trabalham com render fora do tempo real, onde um quadro pode levar minutos. A densidade de malha que faz sentido ali é ordens de grandeza maior do que a que cabe no teto por quadro declarado no capítulo anterior. O modelo está correto. É bonito. E chega pesado demais para o lugar onde vai ser usado.
O segundo é o material, ajustado sob a iluminação da ferramenta, que é montada para produzir uma imagem específica. A cena de destino tem outra iluminação, frequentemente mais pobre. A peça chega escura, ou lavada, ou com um brilho que não existia no ajuste original. O terceiro é a escala, o mais banal e o mais frequente dos três. Um modelo exportado em centímetros para um ambiente que trabalha em metros chega cem vezes maior. O sintoma é espetacular e imediato, o que faz dele o menos perigoso.
Os três têm origem comum, e nomeá-la ajuda mais do que decorar a lista. A ferramenta de autoria é um ambiente completo, com iluminação própria, unidade própria e um destino de render próprio. Ela ajusta o modelo para o ambiente dela. Exportar é tirar o modelo de um contexto e pô-lo em outro que faz suposições diferentes sobre as mesmas três coisas. Daí decorre a única defesa que funciona de forma consistente: conferir os três no destino, e não na origem. Abra o modelo no ambiente em execução. Leia a contagem que ele acrescentou. Olhe-o sob a iluminação da cena de verdade, e meça uma dimensão conhecida dele contra uma peça já existente.
Há uma perda menos visível em começar pela ferramenta externa, e ela é de linguagem. A ferramenta resolve os quatro atributos de uma malha por quem a usa, e não os ensina. Quem nunca escreveu uma normal à mão não diagnostica a peça que chegou escura. A categoria “normal invertida” não está no vocabulário disponível, e a busca começa e termina na iluminação — o único lugar que aquele vocabulário nomeia. Quem nunca distribuiu uma coordenada de textura lê o desenho esticado como problema da imagem, porque é ali que ele aparece.
O alcance desse argumento precisa ficar exato. Ferramentas de autoria não são um estágio anterior a superar, e escrever tudo à mão não é decisão correta em projeto algum de tamanho sério. O que se defende é a ordem: escrever à mão uma vez, primeiro, para adquirir os nomes das coisas. As ferramentas entram depois, com esses nomes na mão. Quem sabe pedir uma contagem compatível com tempo real, uma superfície ajustada sob a iluminação de destino e uma escala declarada em metros está fazendo três pedidos específicos e verificáveis. Alguém que peça “um modelo bonito da engrenagem” está delegando as três decisões junto com a forma.
1.5 O que se vê e o que colide
A caixa contra a qual se testa contato é maior que a peça em toda direção.
Duas peças da oficina apresentam o mesmo sintoma para quem olha só a tela. Uma gruda na mão a um palmo de distância. A outra atravessa o encaixe como se ele não estivesse ali. A tela mostra a malha nos dois casos, e o comportamento não vem da malha.
Pense em como se estaciona um carro. Ele tem retrovisor, para-choque, espelho e maçaneta, e ninguém estaciona pensando em nenhum dos quatro. Pensa-se no retângulo que o carro ocupa, e esse retângulo é maior que o carro em toda direção. O retângulo é mais simples e mais generoso que o objeto. Ele responde rápido à única pergunta que interessa naquele momento: se o carro cabe. Um modelo fiel, com espelhos e maçanetas, responderia com mais trabalho e pior resultado — acusaria folga onde não há e passagem onde não cabe braço.
O volume de contato de uma peça é a forma simples contra a qual se testa proximidade e toque, mantida ao lado da malha que se exibe.
Ele se deriva da geometria da peça e vive no espaço local dela. Assim ele gira, escala e muda de pai junto com a peça, sem recálculo e sem que ninguém precise mantê-lo sincronizado.
O critério que decide a forma do volume é o comportamento pretendido na manipulação, e a semelhança com a silhueta é uma consequência ocasional desse critério. Testar contra a malha completa custa uma comparação por triângulo a cada consulta e entrega uma superfície cheia de reentrâncias, por onde a mira escapa em lugares que quem manipula não tem como prever.
A palavra que a definição põe no centro é comportamento. Semelhança e fidelidade ficam de fora. Um volume de contato bom é o que produz a interação pretendida. Ele se parece com a peça na medida em que isso ajuda a produzi-la, e nem um pouco além.
Essa é a leitura que mais custa a entrar, porque a leitura concorrente é atraente e chega primeiro. Ela diz que o volume de contato seria a malha simplificada, uma versão de menos triângulos da mesma forma. A caixa da engrenagem grande derruba a leitura sozinha. Ela mede 19,5 por 5,6 por 19,6 centímetros, cobre os vales entre os dentes, e sobra dois centímetros para fora da peça em cada direção. Não há simplificação alguma ali. O que existe é outra forma, escrita para outro propósito.
flowchart TB
NO["nó da peça na árvore da cena"]
NO --> MALHA["malha exibida<br/>224 triângulos, catorze dentes<br/>responde: o que o olho vê"]
NO --> VOL["volume de contato<br/>uma caixa, seis planos<br/>responde: a mira apanhou a peça"]
MALHA --> CRIT1["critério: a forma da peça de verdade"]
VOL --> CRIT2["critério: o comportamento pretendido<br/>na manipulação"]
VOL --> LOCAL["vive no espaço local do nó<br/>gira, escala e muda de pai junto, sem recálculo"]
VOL --> FOLGA["silhueta mais a folga<br/>em cada direção"]
FOLGA -.->|"grande demais"| D1["captura o que passou perto:<br/>a peça gruda no ar"]
FOLGA -.->|"pequena demais"| D2["recusa o que já encostou:<br/>a tentativa seguinte vem com força"]
A malha já existe e descreve a peça com exatidão, o que torna tentador usá-la no teste. O argumento do custo aparece primeiro e é o menos importante dos dois. O custo é real. A engrenagem grande tem 224 triângulos, e testar um ponto contra ela significa 224 comparações. Multiplique por cinco peças, dois ponteiros e noventa consultas por segundo. Numa máquina de vídeo integrado, o trabalho deixa de ser desprezível.
Acontece que o segundo argumento é mais forte, e não é de desempenho. Testar contra a malha exata está errado. Ninguém encaixa uma peça pelo flanco de um dente específico. Quem manipula mira a peça inteira, e a peça inteira, para efeito de mira, é a silhueta dela. A malha exata transforma cada vale entre dois dentes numa armadilha. O dedo entra pelo vale, o teste responde que não há contato, e a pega falha. Quem usa vê a mão em cima da engrenagem e nada acontecendo — com a diferença entre pegar e não pegar valendo um milímetro de deslocamento lateral.
A caixa é derivada da geometria da peça, e não do nó já montado na cena. A diferença parece de implementação e decide comportamento. Derivada da geometria, a caixa nasce no sistema de coordenadas da própria peça. Ali ela acompanha de graça tudo o que acontece com a peça. Girar a peça gira a caixa. Escalar a peça escala a caixa. Prender a peça a outro objeto leva a caixa junto. Ninguém escreve uma linha para manter as duas sincronizadas, porque elas não são duas coisas que possam sair de sincronia.
Medida a partir do nó montado, a caixa sairia em coordenadas de mundo, e o mundo se move. Ela se desprenderia da peça no primeiro deslocamento. Recalculá-la a cada quadro traria efeito pior, porque a caixa alinhada aos eixos do mundo cresce quando a peça se inclina. Uma engrenagem inclinada a quarenta e cinco graus ganharia um volume bem maior do que em repouso. A captura ficaria mais fácil num ângulo do que no outro, e nada no código explicaria por quê.
Há um segundo motivo para não medir o nó, mais sorrateiro que o primeiro. O contorno de depuração é filho do próprio nó, e é sempre um pouco maior que a caixa que ele desenha. Medir o nó inteiro incluiria o contorno na conta, e cada recálculo engordaria a caixa sobre a caixa anterior. A peça ficaria mais fácil de apanhar a cada vez que alguém pedisse a medida.
1.6 Um número decide se a peça gruda no ar
Doze centímetros do centro da engrenagem: com um valor de folga o volume não captura, com outro captura.
Uma discussão sobre folga entre duas pessoas degenera rápido. Cada uma tem uma intuição sobre quanto é generoso demais, nenhuma tem argumento, e a conversa termina em preferência estética disfarçada de decisão técnica.
A folga é a distância acrescentada ao volume de contato em cada direção, além da extensão da malha que ele representa.
Ela erra para os dois lados, com sintomas opostos. Folga grande captura o que passou perto, e a peça responde a quem não a tocou. Folga pequena recusa o que já encostou, a tentativa seguinte é feita com mais força, e a força piora a mira.
A folga é decidida por peça, e o número anda junto da razão dele. Peça fina pede folga pequena: a folga que serve para apanhar uma peça grande cerca a peça fina de um volume feito quase só de ar, e qualquer mira que cruze a vizinhança a rouba do alvo pretendido.
1.6.1 Doze centímetros do centro
Ponha um ponto de teste a 12 cm do centro da engrenagem grande, deslocado no eixo horizontal. É o eixo em que a peça é mais larga. Doze centímetros é fora da peça com margem confortável, e ali a mão de quem usa ainda não encostou em nada.
Com a folga adotada de 2,0 cm, a meia-extensão da caixa naquele eixo é de 9,8 cm. O volume não captura o ponto. É o resultado pretendido. Com uma folga de 6,0 cm, a meia-extensão vai a 13,8 cm, e o volume captura. Esse segundo caso é a peça grudando em quem só passou perto, medido em vez de discutido. Ninguém discorda de um booleano medido com o mesmo ponto de teste nos dois casos.
A definição não oferece valor padrão, e a recusa é de quem a escreveu. Um número “que costuma servir” é exatamente aquele que ninguém revisa depois. Ele chega com autoridade de convenção, atravessa o projeto sem ser questionado, e produz o comportamento errado em metade das peças. O projeto que acompanha esta leitura derruba a execução quando uma peça manipulável não tem folga declarada, e derruba de propósito.
Olhe dois números lado a lado. O eixo da oficina leva folga de 0,8 cm, a menor da lista. A caixa dele mede 4,0 por 23,6 por 4,0 centímetros. A engrenagem grande leva 2,0 cm. Por que o eixo leva menos da metade? Porque ele é fino. Aplicar nele os dois centímetros da peça maior daria uma caixa quase toda vazia. O miolo de peça ocuparia uma fração pequena do volume, e o resto seria ar declarado como peça. Uma mira que passasse a dois centímetros do eixo o capturaria, sem nenhuma intenção de pegá-lo. E o capturaria disputando com a peça que estava de fato sendo mirada atrás dele.
Esse é o defeito que mais irrita quem usa, porque não parece defeito. A peça errada é apanhada, quem manipula conclui que errou a mira, tenta de novo com mais cuidado, e apanha a peça errada outra vez. O ambiente parece impreciso, e está fazendo exatamente o que foi mandado fazer.
Antes de seguir. Duas peças paradas na bancada, cujos volumes se interpenetram, vão brigar pela mesma pega no dia em que houver pega. Como você descobre isso hoje, antes de existir qualquer manipulação, sem abrir o código? A resposta é a próxima subseção, e ela custa um botão.
1.6.2 Desenhar o que não se desenha
Onde mora a justificativa de uma folga? A resposta natural é o comentário ao lado da constante, e ela é insuficiente por um motivo mecânico: comentário não sai do arquivo. Quem lê um relatório de volumes vê que o eixo tem folga de 0,8 cm. Não tem como saber se aquele número foi pensado ou digitado. As duas coisas parecem idênticas depois de escritas.
o volume registrado com a folga e a razão dela, em src/bancada/content/colisao.ts
export interface VolumeDeContato {
/** O nó cuja forma visível este volume representa. */
readonly no: Mesh;
/** Meia-extensão da caixa, no espaço local do nó, já com a folga somada. */
readonly meiaExtensao: Vector3;
/** Centro da caixa no espaço local do nó. Raramente é a origem: malha assimétrica desloca. */
readonly centroLocal: Vector3;
/** Folga adotada, em metros, e a justificativa dela em uma frase. */
readonly folga: number;
readonly razaoDaFolga: string;
}A razão viaja com o número até o relatório, guardada como dado no mesmo registro. O efeito mais útil dessa estrutura não está no texto que ela produz. Está na obrigação que ela cria: quem escolhe um número precisa escrever a razão na mesma linha, no instante da escolha. Um campo de texto vazio é visível. Uma justificativa que nunca existiu na cabeça de ninguém não é. A prática tem limite, e ele é fácil de enunciar — ela não impede que alguém escreva “porque sim” no campo, e nenhuma estrutura de dados impediria. O que ela produz é uma frase ruim, escrita e legível, no lugar de uma ausência silenciosa.
Duas outras decisões acompanham a caixa, e as duas são de aritmética por quadro. A folga é somada uma vez, na criação, e não a cada teste. Guardar a meia-extensão crua e somar a folga em cada comparação daria três somas por consulta, multiplicadas pelo número de volumes e de ponteiros ativos. Somando na criação, o teste de contenção fica com três comparações e nada mais.
A segunda é o instrumento. Cada volume de contato ganha um contorno em linha, filho do próprio nó da peça, desligado por padrão e ligado por um botão. Veja o que acontece com ele ligado. Os dois defeitos que tinham o mesmo sintoma ficam distintos em um olhar. A peça que gruda longe aparece envolvida por uma caixa que engole a vizinha. A peça que atravessa o encaixe aparece com uma caixa menor que a própria silhueta. Um instante de observação substitui uma sessão inteira de tentativa.
O contorno é criado sempre, junto com a caixa, e nasce escondido. Montá-lo sob demanda economizaria memória enquanto ninguém estivesse olhando. E mudaria o que ele desenha: passaria a desenhar o estado do momento em que o pedido chegou, recalculado ali. O instrumento que existe para mostrar a caixa registrada deixaria de mostrar a caixa registrada. Instrumento de depuração que altera o que ele mede é pior do que instrumento nenhum, porque produz confiança onde não deveria haver. O botão que liga o contorno vive na página, e não dentro da cena. A escolha é temporária e tem razão de ordem: ainda não existe ponteiro, e sem ponteiro não há como apertar nada dentro do ambiente. O comando desce para o painel preso à bancada quando houver com o que apontar para ele.
O contorno tem um limite, e ele aparece na primeira vez que alguém precisa comparar duas caixas. A olho, elas parecem próximas ou parecem distantes; ninguém estima dois centímetros olhando uma projeção em perspectiva numa tela. Por isso o instrumento tem uma segunda metade, e ela é texto. O relatório traz cada volume em centímetros, com as três medidas, a folga adotada e a razão dela ao lado.
A divisão de trabalho entre os dois instrumentos
O contorno responde onde: que caixa está no lugar errado, que duas se sobrepõem, que uma ficou menor que a peça. O relatório responde quanto: se a diferença é de dois centímetros ou de dois milímetros, e se a folga que produziu aquilo tinha razão. Uma pergunta é espacial e se responde olhando; a outra é numérica e não se responde olhando, por mais treinado que seja quem olha. O relatório tem ainda uma utilidade que o contorno não pode ter: ele é lido por quem não está com o ambiente aberto. E deixa de fora exatamente uma coisa — se duas caixas se cruzam. Cruzamento depende da posição de cada peça na cena, e a lista traz medidas locais.
O critério de decisão que sobra daqui serve a qualquer instrumento que você venha a construir adiante. Quando um medidor puder ser construído no momento da leitura ou mantido desde o registro, escolha o segundo, e pague a memória. Quando uma pergunta for espacial e outra for numérica, construa dois instrumentos, e não um que tente as duas.
1.7 O quarto estado da Bancada
As mesmas peças do estado anterior, agora com dente, faceta e superfície, sem que a árvore tenha sido remontada.
O estado anterior da Bancada — a oficina de montagem servida em três regimes pela mesma URL — mostrava um tampo, um suporte, cinco peças soltas e um painel, todos em caixas e cilindros cinzentos. O parentesco estava justificado, o laço andava contra o relógio, e o envelope do quadro tinha teto declarado e nada de pesado a que atribuir culpa.
Agora a mesma cena sobe e é vestida. A engrenagem grande tem catorze dentes com flanco chapado. A pequena tem a mesma forma em escala menor. O eixo é um prisma de doze lados que passa por cilindro à distância de trabalho. O corpo continua sendo uma caixa e a tampa continua sendo uma placa, as duas por decisão escrita.
a composição do marco, em src/demos/04_demo.ts
// ---------------------------------------------------------------------------
// Marco 04 — a forma das peças, e o volume que decide o encaixe.
//
// A cena do módulo anterior tinha caixas de posição correta e forma provisória.
// Aqui cada peça ganha a sua geometria — perfil extrudado, dentes de engrenagem —
// e, junto, um volume de contato que não é a silhueta dela.
//
// A distinção é o assunto do módulo: o que o olho vê é a malha; o que decide se
// a mira apanhou a peça é a caixa. Confundir as duas é o que faz uma peça grudar
// em quem só passou perto, e a folga de cada uma tem razão declarada.
//
// Ponto de entrada do MARCO 04, imutável (`specs/marcos-executaveis.md`).
// ---------------------------------------------------------------------------
import { montarPalco, type Palco } from '../bancada/core/palco';
import { montarCena, type CenaDaBancada } from '../bancada/core/cena';
import { Relogio, type Amostra } from '../bancada/core/relogio';
import { Orcamento, TETO_DESKTOP_MS } from '../bancada/core/orcamento';
import { montarLaco, type Laco } from '../bancada/core/laco';
import {
vestirCena,
compararFolgas,
type Conteudo,
type ComparacaoDeFolga,
} from '../bancada/content/pecas';
import { linhasDoCatalogo } from '../bancada/content/materiais';
import { montarConteudo } from '../bancada/relatorio/conteudo';
const TETO_DO_QUADRO_MS: number = TETO_DESKTOP_MS;
// O ponto de teste fica a doze centímetros do centro da engrenagem grande, que é
// fora dela por margem confortável. A folga adotada não o alcança; uma folga
// generosa alcança. É a captura do que passou perto, medida em vez de discutida.
const DISTANCIA_DE_TESTE_M: number = 0.12;
const FOLGA_GENEROSA_M: number = 0.06;
function criarNo<T extends HTMLElement>(tag: string, pai: HTMLElement, id?: string): T {
const no: T = document.createElement(tag) as T;
if (id !== undefined) {
no.id = id;
}
pai.appendChild(no);
return no;
}
const raiz: HTMLElement = document.getElementById('bancada') ?? document.body;
const titulo: HTMLHeadingElement = criarNo<HTMLHeadingElement>('h1', raiz);
titulo.textContent = 'Bancada — a forma que se vê e o volume que decide';
const canvas: HTMLCanvasElement = criarNo<HTMLCanvasElement>('canvas', raiz, 'cena');
const botaoVolumes: HTMLButtonElement = criarNo<HTMLButtonElement>('button', raiz, 'volumes');
botaoVolumes.type = 'button';
botaoVolumes.textContent = 'Mostrar os volumes de contato';
const raizConteudo: HTMLElement = criarNo<HTMLElement>('div', raiz, 'conteudo');
const palco: Palco = montarPalco(canvas);
const cena: CenaDaBancada = montarCena();
const relogio: Relogio = new Relogio();
const orcamento: Orcamento = new Orcamento(TETO_DO_QUADRO_MS);
const laco: Laco = montarLaco(palco, cena.sala, relogio, orcamento);
const conteudo: Conteudo = vestirCena(cena);
function frasesDaFolga(): string {
const c: ComparacaoDeFolga = compararFolgas(conteudo, DISTANCIA_DE_TESTE_M, FOLGA_GENEROSA_M);
const adotada: string = c.capturaComAFolgaAdotada ? 'captura' : 'não captura';
const generosa: string = c.capturaComAFolgaGenerosa ? 'captura' : 'não captura';
return (
`Um ponto a ${(c.distanciaDeTeste * 100).toFixed(0)} cm do centro da engrenagem grande: ` +
`com a folga adotada de ${(c.folgaAdotada * 100).toFixed(1)} cm, o volume ${adotada}; ` +
`com uma folga de ${(c.folgaGenerosa * 100).toFixed(1)} cm, ${generosa}. ` +
`O segundo caso é a peça grudando em quem só passou perto.`
);
}
montarConteudo(
raizConteudo,
conteudo.inventario.map(
(l) => `${l.peca}: forma ${l.origem}, ${l.triangulos} triângulos e ${l.vertices} vértices.`,
),
linhasDoCatalogo(conteudo.catalogo),
conteudo.contato.linhas(),
frasesDaFolga(),
);
// Os volumes ficam invisíveis por padrão porque a cena deve mostrar o que o olho
// veria. Exibi-los é uma ferramenta de quem constrói, não parte do ambiente.
botaoVolumes.addEventListener('click', () => {
const exibindo: boolean = conteudo.contato.alternarExibicao();
botaoVolumes.textContent = exibindo
? 'Esconder os volumes de contato'
: 'Mostrar os volumes de contato';
});
laco.aoPasso((amostra: Amostra) => {
cena.eixo.rotation.y += amostra.delta * 0.6;
});
laco.iniciar();
A composição continua apresentando objetos uns aos outros, como no estado anterior, e ganha uma linha nova. A rotina que veste a cena recebe a cena pronta e devolve um inventário. Nenhum nó é criado, nenhum é removido, nenhum troca de pai — a estrutura continua pertencendo ao arquivo que a montou.
Repare no que a página exibe além do canvas. Há um botão e há três seções de texto. Os dois existem porque a metade mais cara deste estado não cabe na imagem, e um estado que só se demonstra pela imagem estaria escondendo justamente o que ele acrescentou.
1.7.1 Os cinco volumes, ligados por um comando
O botão abre dizendo que vai mostrar os volumes de contato. Um clique, e cinco caixas em linha aparecem sobre as peças, cada uma um pouco maior que a silhueta que envolve. O rótulo do botão troca para o texto oposto, e o texto novo vem do valor que a própria função de alternância devolve.
Com as caixas à vista, duas patologias que têm o mesmo sintoma na tela ficam distintas em um olhar.
A primeira é a caixa que engole a vizinha. Duas peças próximas cujos volumes se interpenetram vão disputar a mesma pega no dia em que houver pega, e a disputa será resolvida por uma ordem de teste que ninguém escolheu. Na tela, sem as caixas, as duas peças parecem apenas próximas.
A segunda é a caixa menor que a silhueta, que acontece quando a folga é pequena demais para a peça ou quando o centro do volume ficou deslocado. A peça aceita a mira num lado e a recusa no outro, e quem tenta apanhá-la conclui que errou o gesto.
Nenhuma das duas produz sintoma antes de existir manipulação. As duas se corrigem em segundos enquanto a oficina tem cinco peças, e a correção da primeira costuma ser afastar uma delas dez centímetros.
1.7.2 A folha do conteúdo
A terceira coisa que a página do marco escreve é texto, em três blocos, e ela responde ao que o contorno não responde.
O primeiro bloco é o inventário de forma. Cinco linhas, uma por peça, cada uma dizendo se a forma é autorada ou pedida à biblioteca, com a contagem de triângulos e de vértices ao lado. A soma das cinco linhas é 440 triângulos: 224 na engrenagem grande, 144 na pequena, 48 no eixo e 12 em cada primitiva.
O segundo bloco é o catálogo de superfícies, e ele abre com o número que interessa: quatro materiais distintos na cena. As duas engrenagens aparecem apontando para a mesma instância de latão, e ver isso escrito é diferente de acreditar que está assim.
O terceiro bloco é a folha dos volumes. Cada caixa em centímetros, com a folga adotada e a razão dela na mesma linha. A linha do eixo diz 4,0 por 23,6 por 4,0 centímetros, folga de 0,8 cm, e por que essa é a menor da lista: a peça é fina, e uma folga generosa a cercaria de um volume feito quase só de ar.
Fecha a página uma frase que sai de um teste executado na abertura. Um ponto a 12 cm do centro da engrenagem grande: com a folga adotada de 2,0 cm, o volume não o captura; com uma folga de 6,0 cm, captura. A frase é gerada pela comparação, com os números que a comparação produziu, e não digitada por alguém que se lembrou do resultado.
Essa última linha é a que encerra a discussão sobre folga em qualquer grupo. Ninguém discorda de um booleano medido com o mesmo ponto de teste nos dois casos.
1.8 O que fica escrito para o próximo passo
O mais caro que a oficina ganhou aqui não aparece em fotografia nenhuma.
Volte à engrenagem do início, a dos catorze dentes com flanco chapado e vale fundo. Agora ela tem nome para as quatro listas que a formam. Tem uma razão para o número de dentes, uma superfície declarada por matéria, e uma caixa invisível com dois centímetros de folga justificada.
flowchart TB
F["as seis conferências do estado"]
F --> V["três exigem movimento"]
F --> L["duas exigem ler uma lista"]
F --> I["uma exige ligar um instrumento"]
V --> V1["girar cada peça contra a luz:<br/>nenhuma lateral escurece ao encarar a fonte"]
V --> V2["olhar o eixo ampliado:<br/>doze lados, normal decidida por face"]
V --> V3["mover a peça e o pai dela:<br/>o volume acompanha sem recálculo"]
L --> L1["densidade com razão que cita<br/>tamanho da peça e distância de leitura"]
L --> L2["cada folga com a justificativa<br/>na mesma linha do número"]
I --> I1["contorno ligado por comando:<br/>nenhum par de caixas se sobrepõe em repouso"]
- Parte das peças tem geometria escrita no projeto, e a escolha entre autorar e pedir à biblioteca tem razão dita em voz alta.
- Nenhuma face está com a normal invertida. Cada peça foi girada devagar contra a luz direcional, e a lateral escureceu quando devia clarear em nenhuma delas.
- A densidade de cada malha tem justificativa que menciona o tamanho da peça e a distância de onde ela é vista.
- Os materiais são compartilhados entre peças de mesma superfície, e o catálogo cabe num olhar.
- Toda peça manipulável tem volume de contato, e cada folga tem razão escrita ao lado do número.
- Os volumes podem ser exibidos por comando, e nenhum par de caixas se sobrepõe com as peças em repouso.
Nenhuma das seis se faz olhando uma captura de tela. Três exigem movimento, duas exigem ler uma lista, e uma exige ligar um instrumento. A conferência das normais é a que tem o melhor retorno por minuto gasto. Girar cinco peças contra a luz leva menos de dois minutos, e elimina a tarde inteira descrita lá atrás. Ela também precisa ser refeita a cada peça nova, porque o defeito nasce com a peça.
O trabalho feito aqui se divide em duas metades com destinos diferentes. A primeira — malha, perfil, densidade, superfície — foi gasta e entregue: a oficina parece uma oficina, e isso é resultado hoje. A segunda foi guardada. Os cinco volumes de contato, as cinco folgas com razão escrita e o comando que os exibe não fizeram nada até agora. Nem farão, até que exista alguém apontando para uma peça.
As duas metades também se conferem em ritmos diferentes. A forma se confere quando é escrita, uma vez, e depois só volta a exigir atenção se o perfil mudar. O volume se confere quando é escrito, e outra vez sempre que a peça mudar de tamanho, de posição ou de vizinhança — porque qualquer uma das três altera se ele encosta em alguma coisa.
Escrever o volume de contato agora custa decidir uma folga e digitar uma linha por peça. Escrevê-lo depois, com a manipulação já implementada, custa voltar a um código que funcionava e acrescentar nele uma camada que ele não previa. Essa é a aritmética inteira, e ela pode ser feita hoje por qualquer pessoa que tenha as duas contas à mão.
Há uma assimetria desconfortável entre as duas metades, sem solução elegante. A primeira se defende sozinha: a oficina está ali, com dentes e facetas, e qualquer pessoa vê que alguém trabalhou. A segunda só pode ser defendida por argumento, porque o que ela produziu foi a ausência futura de um conjunto de problemas. A peça que não gruda no ar. A mira que não rouba o alvo vizinho. A sessão de depuração que não aconteceu. Nada disso é exibível, e quem construiu essas ausências não tem como mostrá-las a ninguém.
O que vem em seguida cobra as duas metades, em ordem. Primeiro entram modelos vindos de fora, com contagem de triângulos decidida por outra pessoa. Os 440 anotados aqui deixam de ser curiosidade e passam a ser o único termo de comparação disponível. Depois cada caixa invisível ganha, pela primeira vez, algo contra o que ser testada.
Tarefa 1: Construir geometria própria em código
Ao menos parte dos objetos da cena nasce de geometria escrita no próprio ambiente, com vértices, faces, normais e coordenadas de textura decididos por quem constrói. Material e propriedades de superfície entram junto, com o custo em tempo real pesando na escolha.
O que fica pronto é um conjunto de objetos do domínio construídos assim, integrados à hierarquia da cena e posicionados por decisão de projeto. É a peça que garante que a cena tenha sido composta, e não recebida inteira de um exemplo pronto.
Tarefa 2: Separar o que se vê do que colide
A malha exibida e o volume contra o qual se testa contato raramente são o mesmo objeto. A separação precisa existir desde já: descobri-la tarde significa depurar colisões que acontecem em lugar diferente do que a tela mostra.
A tarefa fecha quando cada objeto manipulável da cena tem sua forma visível e seu volume de contato definidos em separado, com a relação entre os dois registrada. Volume folgado demais captura o que passa perto; apertado demais recusa o que já encostou.