Preenchendo uma grelha com quadriláteros: o que funciona na prática
Quando se pede para crie um mosaico na malha quadriculada usando somente quadriláteros, a maioria das pessoas pensa logo em quadrados perfeitos. Isso é trivial e não resolve o problema real. A questão séria é como cobrir toda a malha sem buracos e sem sobreposições, usando apenas quadriláteros — retângulos, losangos, trapézios, trapezoides genéricos — quando as restrições do desenho ou do algoritmo tornam os quadrados impossíveis ou ineficientes. Já perdi meia manhã num projeto de texture packing onde a regra era exatamente essa: malha quadrada, só quadriláteros permitidos, mas algumas células estavam obstruídas por obstáculos. Tentar forçar retângulos de 1x1 acabou gerando fragmentos irregulares que quebravam o pipeline downstream. A solução foi trocar a estratégia de preenchimento e aceitar quadriláteros não-retangulares nas regiões de transição.
crie um mosaico na malha quadriculada usando somente quadriláteros
O primeiro passo é definir claramente o que conta como quadrilátero válido no seu contexto. Na maioria das implementações práticas, um quadrilátero é qualquer polígono de quatro vértices cujos lados não se cruzam e cuja área é estritamente positiva. Isso inclui quadrados, retângulos, losangos, trapézios e trapezoides arbitrários. Não inclua self-intersecting quads nem degenerados com área zero — eles vão estourar o renderer ou o motor de física mais tarde. Depois, escolha a abordagem de preenchimento. Existembasicamente três caminhos que eu vejo funcionando no mundo real:
O primeiro é o preenchimento por retângulos contíguos. Você agrupa células vizinhas livres em retângulos máximos possível e os reporta como quadriláteros. Funciona bem quando a geometria é axial e as obstruções são poucas. Desvantagem clara: em regiões com buracos irregulares, você acaba gerando muitos retângulos pequenos e fragmentados, o que infla a contagem de primitivas sem ganho real. O segundo caminho é o preenchimento com quads deformados. Aqui você parte da malha base e, sempre que um retângulo perfeito não cabe por causa de obstáculos ou limites curvos, você distorce os vértices do quad para contornar o problema. O resultado é um quadrilátero válido matematicamente, ainda que visualmente torto. Isso é útil em tesselações adaptativas e em bump mapping de UVs, mas exige que o resto do seu sistema saiba lidar com quads não-ortogonais. Se o downstream assume ortogonalidade, você vai ter artefatos.
O terceiro é o preenchimento híbrido, que é o que eu uso na maior parte do tempo. Você combina retângulos onde possível e substitui por quads deformados apenas nas zonas de transição. A regra prática que eu adotei é: se um retângulo de pelo menos 2x2 cabe, use o retângulo. Se só cabe uma faixa estreita ou uma forma em L, considere um quad deformado ou divida em dois triângulos e trate como caso especial. Em projetos reais, essa abordagem costuma reduzir a contagem de quads entre 30% e 50% comparado ao uso exclusivo de retângulos unitários, dependendo da densidade de obstruções. Um detalhe que os tutoriais não costumam mencionar e que causa dor de cabeça constante é a orientação dos vértices. Quadriláteros devem ter seus vértices ordenados consistentemente, seja horário ou anti-horário, e isso precisa valer para todos os quads do mosaico. Se misturar orientação, o culling vai falhar e você terá faces que piscam ou somem dependendo do ângulo de câmera. Eu levei duas horas num debugging ruim até perceber que um lote de quads havia nascido com ordem inconsistente por causa de uma troca de eixos na conversão de coordenadas da malha para o espaço do objeto.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Outro ponto prático: validação. Antes de enviar o mosaico para qualquer pipeline, valide cada quad. Verifique se os quatro vértices são distintos, se o polígono é simples (sem auto-interseção) e se a área é positiva. Um teste rápido de soma cruzada dos vetores dos lados detecta a maioria dos casos problemáticos. Se algum quad falhar, recalibre os vértices ou descarte a célula e trathe como vácuo. É melhor ter um buraco conhecido do que um quad degenerado rodando escondido. Quanto à complexidade, um algoritmo ingênuo de backtracking para cobrir a malha pode levar tempo exponencial em grades médias. Para uma grade de 32x32 com cerca de 40% de obstruções aleatórias, soluções por força bruta podem levar minutos ou até horas. Uma heurística gulosa com lookahead de duas camadas resolve na maior parte dos casos em menos de dois segundos em CPU moderna. Se precisar de garantia de optimalidade, formulário como problema de coveramento exato e use um solver DPLL ou um algoritmo de dancing links, masprepare-se para custos computacionais maiores e tempo de desenvolvimento adicional.
Se o seu objetivo é puramente visual, considere se realmente precisa de quadriláteros. Triângulos são mais previsíveis em rasterização e têm suporte universal. Quadriláteros fazem sentido quando o downstream explora interpolacão bilinear ou quando a topologia da grade precisa ser preservada para texturização. Fora isso, você está adicionando restrição sem ganho proporcional. Para implementação, um esqueleto mínimo funciona assim: inicialize uma grade booleana, itere por cada célula livre, tente formar o maior retângulo possível começando nessa célula, registre o retângulo como quad ortogonal, marque as células como usadas e prossiga. Quando não houver retângulo de tamanho útil, calcule um quad deformado ajustando vértices aos vizinhos livres disponíveis, valide, registre e marque. Mantenha uma lista separada de quads ortogonais e deformados para facilitar tratamento diferenciado depois.
Existe ainda o problema das bordas da malha. Quads que tocam o limite precisam ter seus vértices externos snapados para a fronteira válida, senão o bounding box do mosaico cresce de forma não intencional e o culling perde eficiência. Eu resolvi isso aplicando uma projeção clamping pós-geração, que recorta qualquer vértice para fora dos limites da grade de volta para a borda mais próxima. O custo é baixo e evita metade dos bugs de clipping que aparecem depois. Se você está trabalhando com ferramentas existentes, engines como Unity e Unreal aceitam quads nativamente, mas exigem que a malha sejawatertight e bem orientada. Ferramentas de mesh generation como Blender com o plugin QuadriFlow fazem um trabalho razoável, mas impor a restrição de "só quadriláteros" manualmente ainda pede script customizado. Um script Python simples que percorre a grade e gera vertices + indices por quad resolve para protótipos. Para produção, vale a pena empacotar em um módulo separado com validação embutida e logging de quads rejeitados, porque eventualmente algum edge case vai passar se você não estiver monitorando.
Resumindo sem dramatismo: a técnica é viável, tem armadilhas previsíveis e a escolha entre retângulos puros, quads deformados ou mistura depende diretamente do que seu pipeline suporta. A validação é obrigatória, a consistência de orientação é obrigatória, e a heurística gulosa com lookahead é suficiente para a maioria dos cenários prticos. Se o seu caso exige optimalidade estrita ou grade muito grande com padrões de obstrução complexos, investi em um solver adequado desde o início, senão você vai gastr mais tempo remendando do que desenvolvendo.