Sobre gráficos 3D em palavras simples

Parte 1. Introdução


Olá, meu nome é careca. Eu trabalho como programador de gráficos há vários anos, portanto, embora eu não seja de forma alguma um especialista, parece que eu já entendo muito sobre tudo relacionado ao trabalho com gráficos.

A ideia desta série de posts está pairando há muito tempo em algum lugar na periferia da minha mente e surgiu novamente depois de ler um artigo interessante com uma análise do mais recente Deus Ex .

Parece-me que os gráficos, e especialmente a complexidade que ele atinge nos jogos modernos, são um tópico interessante. Pouquíssimas pessoas têm curiosidade de se aprofundar em todos os detalhes, mas acredito que há tópicos que interessam a todos. Eu acho que a maioria das pessoas que jogava jogos estava curiosa sobre como esses ou aqueles efeitos foram obtidos, ou com qual tecnologia eles conseguiram criar gráficos tão incríveis em algum novo jogo.


Existem muitos componentes necessários para criar até um jogo 3D simples, sem mencionar um projeto como o Watch Dogs.

Tenho apenas uma idéia geral do que precisa ser considerado neste artigo, mas isso dependerá de quais tópicos causarão interesse. No entanto, a idéia principal é criar uma descrição geral do que está acontecendo dentro do jogo moderno sem assustar nenhum dos leitores - presumo que você não tenha conhecimento de matemática e programação. Se você conhece a diferença entre a CPU e a placa de vídeo e distingue a RAM do disco rígido, isso será suficiente e eu explicarei o resto.

Este artigo será desenvolvido de acordo com o passo a passo de vídeo Let's Play of Watch Dogs da Chip & Ironicus , a fim de estruturar levemente a apresentação. O jogo é conhecido por seus gráficos (e opiniões sobre ele podem ser completamente opostas), e há muitos aspectos que podem ser considerados com exemplos separados. Talvez eu fale sobre outros jogos.

Começarei explicando o básico que é praticamente o mesmo para todos os jogos, mas também analisarei algumas das técnicas e efeitos visuais do Watch Dogs.

Vou usar uma ferramenta chamada RenderDoc , que escrevi no meu tempo livre. É usado para depurar problemas com gráficos - a ferramenta permite decompor um quadro gráfico em partes e, graças a isso, veremos como ele se junta.


Essa animação mostra parte de um quadro que está sendo criado gradualmente no processo de renderização com uma placa gráfica.

A maioria das pessoas sabe que os gráficos de computador (e os de qualquer outro vídeo) consistem em uma série de quadros estáticos, cada um dos quais é exibido por uma certa fração de segundo. No cinema, tradicionalmente usado 24 quadros por segundo (quadros por segundo, FPS), na televisão a frequência é quase a mesma, cerca de 24 a 30 quadros. Nos jogos, o FPS pode ser alterado porque é feito muito trabalho em cada quadro. Uma queda de frequência abaixo de 30 é indesejável, embora isso ocorra com bastante frequência. Geralmente, o limite superior para jogos de console é de 60 FPS. Os desenvolvedores procuram implementar uma frequência de 30 ou 60, que depende dos objetivos do jogo. Em um PC com uma tela com alta taxa de quadros, é possível atingir 90, 120 ou até mais. A razão para esses números específicos é a sincronização vertical (vsync), que discutiremos abaixo.

Mentalmente, podemos olhar para essa tarefa do lado oposto - em vez de ver quão alta é a frequência do FPS, observamos quão pouco tempo é alocado para cada quadro. Se queremos que o jogo funcione com uma frequência de 30 FPS, temos apenas 33 milissegundos para concluir todo o trabalho necessário para o quadro. A 60 FPS, o tempo é metade - cerca de 17 milissegundos. Mesmo para um computador, esse período de tempo não é muito grande, dada a quantidade de trabalho que precisa ser feito. Para se ter uma idéia das quantidades, então, de acordo com estimativas aproximadas, a bala se move cerca de 1 metro por milissegundo.

Falaremos principalmente sobre PCs porque essa plataforma é aberta e não posso falar sobre consoles sem medo de violar acordos de não divulgação (NDAs). Enfim, basicamente vou falar sobre o que não é muito diferente nos consoles, mas se algo ainda diferir, enfatizarei isso. Para plataformas móveis, a maioria das diferenças entre hardware / consoles de PC e hardware móvel não é relevante para o tópico do meu artigo.


Sinceramente, coloquei esta foto aqui para que você entenda que o artigo não terá apenas texto.

É essa tarefa que nos interessa - não nos preocuparemos com a forma como todos os seus cálculos de IA são executados ou com a simulação física para mover objetos. Os limites da disciplina chamada "programação gráfica" são um pouco confusos, mas eu digo que a programação gráfica começa quando temos todas as informações necessárias para construir um quadro: sabemos o que acontece, todas as texturas e modelos estão na memória (não no disco) ), as animações já estão animadas, a física é contada e precisamos apenas desenhar um quadro pronto para exibição na tela.

Acrescento que considerarei um jogo 3D com uma renderização bastante tradicional, como o Watch Dogs - muitos dos princípios básicos se aplicam a jogos 2D, mas é um pouco mais difícil demonstrar conceitos sobre eles. Também explicarei (especialmente para programadores gráficos) que estou me esforçando principalmente para entender, portanto, talvez, usarei explicações bastante duvidosas se elas me permitirem alcançar meu objetivo.

Parte 2. Em que consiste o quadro


Na maioria das vezes, vamos olhar apenas um quadro e falar sobre os blocos de construção que o jogo usa para criar um quadro acabado. Também nesta parte, haverá várias novas fotos bonitas.

Existem várias maneiras de montar uma estrutura a partir de blocos de construção. A imagem final que o player vê não é renderizada instantaneamente. Ele foi desenhado imediatamente há muitos anos, mas os motores gráficos modernos quase sempre usam algum tipo de pré-processamento. Antes de exibir o quadro final na tela, o mecanismo gráfico desenha muitas imagens intermediárias de vários tipos que ajudam no cálculo da imagem final.

Essas imagens são altamente dependentes do tipo de mecanismo e das técnicas que o programador gráfico precisa aplicar. Por exemplo, se ele deseja que a luz do sol crie as sombras corretas, um tipo de imagem será necessário para as sombras. Ele também pode precisar das reflexões corretas no carro dirigido pelo jogador e, para isso, também precisa de outra imagem com reflexões.







Vários exemplos de imagens intermediárias usadas na construção do quadro Watch Dogs.

Neste artigo, não considerarei cada uma das imagens usadas no quadro Watch Dogs, mas apenas as básicas, para que você possa aprender alguma coisa. Esta é uma área em que a pesquisa gráfica está constantemente ocorrendo e novas técnicas estão surgindo. As inovações também surgem em níveis menores, mas quando o marketing informa sobre alguma nova função gráfica, geralmente se refere a essas melhorias.



Cada uma dessas imagens intermediárias também é construída a partir de fragmentos ainda menores. Cada objeto na cena ou um grupo de objetos relacionados é criado separadamente como um modelo texturizado . Ao desenvolver um jogo, os artistas constroem esses modelos em um editor 3D e criam todos os recursos necessários para eles. Em seguida, esses modelos são colocados no mundo usando o editor de níveis e uma cidade virtual é gradualmente construída a partir deles.

Provavelmente, quase todo mundo sabe disso, e se você assistiu ao desenvolvimento de gráficos 3D em tempo real nos últimos 20 anos, sabe como os modelos mais complexos se tornaram hoje. Nos primeiros estágios da formação dos gráficos, o mapeamento de texturas era um processo dispendioso e, se possível, era descartado pintando objetos da mesma cor. As texturas foram deixadas apenas para elementos como olhos ou rostos que realmente precisavam de detalhes.

O modelo 3D consiste inteiramente em triângulos interconectados que formam a forma do objeto. Cada triângulo tem três pontos chamados vértices e, como os triângulos estão conectados, os vértices podem ser compartilhados por vários triângulos. Voltaremos a isso mais tarde, porque os vértices e triângulos são importantes o suficiente. Também vale lembrar que alguns objetos, por exemplo, caracteres ou árvores, devem ser animados antes da renderização. O modelo é criado no formato estático padrão e as animações são aplicadas em cada quadro. Voltaremos a isso também.


Este é um modelo 3D da cabeça de Aiden Pierce após animação. Os triângulos são visíveis porque são desenhados planos e não suavizados, como é geralmente o caso.

Para adicionar mais detalhes ao modelo 3D, as texturas são sobrepostas. As texturas são arquivos regulares de imagem plana, geralmente de tamanho quadrado ou simples, como retângulos com uma proporção de 2: 1. As texturas são sobrepostas no modelo 3D usando um processo mais complexo, que discutirei com mais detalhes abaixo, mas conceitualmente é semelhante ao processo de embrulhar um presente. Em vez de um padrão simples e repetitivo de invólucros de papel, a imagem corresponde exatamente ao tamanho do invólucro. Se você viu modelos de papel para montagem com cola, o princípio é o mesmo.

Essa analogia é mais apropriada do que você imagina, porque essas texturas geralmente são criadas “desenrolando” um modelo 3D em um espaço em branco plano, como é feito com um modelo de papel, após o qual uma textura é desenhada sobre ela. Essa implantação geralmente é realizada automaticamente, mas no caso de objetos particularmente complexos pode ser feito manualmente.


Esta é a textura correspondente ao modelo de cabeça de Aiden Pierce mostrado acima. Existem peças para dentes e língua. Observe que a área acima da testa não é texturizada porque está permanentemente coberta pelo boné de beisebol lendário Aiden Pearce ™.

Nota


Ao desdobrar, algumas partes do objeto que requerem mais detalhes aumentam, enquanto outras diminuem.

Muitas vezes eles falam sobre várias "skins" de modelos, especialmente no caso de personagens personalizáveis. Hoje, o que é chamado de “skin” geralmente se refere a pequenas mudanças no modelo - um novo cinto ou um chapéu diferente -, mas inicialmente esse termo surgiu porque o mesmo modelo foi usado, mas a textura mudou (ou “skin” - literalmente se traduz como "Skin") para criar um personagem com aparência diferente. Ainda hoje, com a ajuda de tais texturas, você pode criar uma grande variabilidade de NPCs ou objetos, o que economiza tempo e dinheiro - você não precisa criar muitos modelos 3D exclusivos. As roupas diferentes que Aiden pode usar geralmente são apenas texturas diferentes do mesmo modelo.


Aqui está um breve trecho da rotação da cabeça do modelo 3D. Sobreposta apenas textura, e nada mais.

No quadro que estamos considerando, existem aproximadamente 1700 objetos renderizados na parte principal de renderização. Alguns deles serão os mesmos modelos - objetos como flores em vasos e latas de lixo nunca são realmente criados separadamente; esse é um modelo ou vários modelos colocados em lugares diferentes. No entanto, a quantidade aproximada de objetos desenhados para completar o quadro é próxima de 4700 - isso nos dá uma idéia de quanto trabalho adicional precisa ser feito além da renderização de todos esses modelos.

Vejamos outro exemplo de um objeto - um boné de beisebol usado por Aiden.



Este é um modelo de boné de beisebol com textura e textura. Pode-se observar que a textura é construída com partes separadas conectadas ao modelo.

Nota


A viseira e a parte principal do boné de beisebol na textura não tocam, porque a digitalização pode ser bastante complicada e, se necessário, pode ser realizada em várias partes diferentes. Às vezes, texturizar um modelo de forma complexa sem problemas visíveis e costuras requer uma quantidade razoável de habilidades.

Os mesmos princípios que vimos com a cabeça de Aiden se aplicam ao boné. De fato, se ignorarmos a textura e os números específicos necessários para realizar o desembrulhamento, o princípio será sempre o mesmo.

Para mostrar o que pode dar errado durante o desenvolvimento e demonstrar como você pode se divertir ao programar gráficos, podemos realizar um pequeno experimento. Como a maioria das texturas tem um tamanho quadrado padrão e o método de agrupar e desdobrar as texturas no modelo também é o mesmo, por que não brincar um pouco com elas? O que acontece se aplicarmos a textura da cabeça de Aiden em um modelo de boné de beisebol?


Já não é muito parecido com o boné de beisebol lendário de Aiden Pierce.

Onde havia um logotipo na textura do boné de beisebol, a orelha e os dentes estão localizados na textura da cabeça. Onde havia uma viseira, havia apenas cabelos na textura da cabeça. A sobreposição é exatamente a mesma, mas uma textura diferente é usada. Obviamente, este exemplo será um erro no jogo, mas pense no que pode ser feito se você animar a textura ou fazê-la tremular - nos jogos, essas coisas são usadas para vários efeitos que você pode notar agora. Em particular, o jogo Saint's Row 4 usa similar para efeitos especiais de "simulação".

Também será útil pensar nas consequências disso - os jogos combinam muito cuidadosamente pares de modelos e texturas, ou seja, os modelos mais exclusivos devem corresponder às suas próprias texturas únicas.

Obviamente, essa regra não é absoluta - em alguns casos, para economizar espaço, a textura é um padrão de repetição padrão que pode ser usado para muitos objetos. Conjuntos de objetos vinculados - por exemplo, bancas de jornais - podem usar a mesma textura para jornais diferentes, com cada jornal ocupando uma pequena fração da textura.

No entanto, isso significa que, para construir a imagem final, todos os blocos de construção devem estar presentes, ou seja, como resultado, muitos modelos e texturas necessários podem ser obtidos. Na próxima parte, falaremos sobre por que alguns aspectos, como a reflexão, são muito difíceis de implementar corretamente. Também falarei sobre como os jogos usam pequenos truques para economizar tempo e recursos.

Parte 3. O que você não precisa desenhar


Freqüentemente, programar gráficos é a tarefa de equilibrar uma dúzia de restrições diferentes para obter o compromisso perfeito. Na última parte, vimos que toda vez que uma cena é desenhada, ela é montada a partir de muitos pequenos blocos de construção - pessoas, carros, sinais de trânsito, edifícios. Tudo o que está na tela é composto de componentes individuais que precisam ser desenhados. Existem várias operações sutis de balanceamento que discutiremos aqui.

O processador central e a placa gráfica trabalham juntos na renderização do quadro. O resto do jogo é executado na CPU, por isso decide quais objetos devem ser desenhados no quadro atual, para onde a câmera está olhando e quais animações são reproduzidas. Uma placa de vídeo é um "cavalo de batalha" que executa todo o trabalho complexo envolvido na renderização de pixels, e é por isso que é um dispositivo especializado separado.

Acontece que tanto a CPU quanto a placa gráfica têm limitações na velocidade ou quantidade de cálculos, mas esses são tipos diferentes de restrições.

Em geral, a CPU está mais interessada em sua parte do trabalho: quantos objetos precisamos desenhar no total? Quão diferentes são esses objetos - são 100 luzes idênticas ou 100 arbustos / plantas / árvores? Esses objetos são animados, eles estão se movendo dinamicamente e quais deles são estáticos ou imóveis?

A primeira coisa que fazemos para reduzir a carga o máximo possível é desenhar apenas o que é visível na tela. Isso parece óbvio, mas a implementação requer um trabalho cuidadoso. Não se esqueça de que construímos cada quadro a partir do zero, portanto, em cada quadro , precisamos olhar para cada objeto e determinar se ele é visível ou não. Isso significa que em todo jogo existe um vazio negro em toda parte após o jogador, e quando ele não olha para objetos e pessoas, eles deixam de existir.


Nesta animação, giramos a câmera, mostrando o vazio atrás do player. Os espectadores atentos perceberão que não está completamente vazio ...

É difícil desenvolver regras práticas nesse caso, mas, em geral, você pode desenhar cerca de 1000 objetos na cena sem se preocupar com a falta de espaço. No entanto, se você precisar renderizar 5.000 objetos, pense em usar truques. Não esqueça que, na maioria dos jogos em que o jogador pode controlar a câmera, não podemos saber em que ângulo ele ficará; portanto, você precisa economizar espaço para manobra.

Acontece que existem muitos truques que permitem usar quase completamente um recurso válido, e eles são especialmente importantes em jogos como o Watch Dogs. Quanto mais perto você estiver das bordas e mais qualidade visual puder obter do mesmo número de objetos, melhor será o jogo.

Mesmo se você olhar o que está à sua frente na cena, isso não significa que é necessário desenhar a cidade inteira. Se houver um edifício enorme à esquerda ou à direita, tudo o que está por trás dele ficará invisível, para que você não possa desenhá-lo. Da mesma forma, alguns objetos à distância se tornam muito pequenos, portanto, não precisamos nos preocupar em desenhar pequenas plantas e arbustos à distância.


Essa animação mostra que se você descer a rua além do que vemos, não haverá nada nas ruas laterais, mas a uma grande distância os detalhes ficarão menores.

De fato, ainda existem muitos objetos nessa cena que se tornarão invisíveis como resultado. Ainda há muito a ser explorado nessa área e várias técnicas sofisticadas devem ser aplicadas. Você sempre precisa fazer compromissos, mas se puder gastar um pouco de tempo ou apresentar uma maneira muito inteligente de evitar renderizar 100 objetos com quase nenhum esforço extra, podemos tornar a cena ainda mais complexa ou mais densa.

Além disso, há outro pequeno problema. Em alguns casos, precisamos desenhar um edifício que mal é visível na tela e vai muito além. Desperdiça recursos. Sempre podemos dividir esses objetos em várias partes, para que cada parte possa ser desenhada ou pulada, ou seja, haverá menos desperdício. No entanto, agora aumentamos o número total de objetos desenhados quando estão na tela e criamos o problema oposto!

Este exemplo é um de centenas, mas é fácil explicar quais decisões precisam ser tomadas e quais experimentos são necessários para encontrar o ponto de equilíbrio perfeito para cada jogo.

Como a ação de nosso tiro da Watch Dogs ocorre na cidade, podemos examiná-lo de cima para entender aproximadamente o que exatamente está sendo desenhado. Nesta imagem estática, é especialmente notável que o Watch Dogs faz o trabalho trimestralmente.


Agora nos afastamos para mostrar a área visível na frente da câmera (desculpe pela instalação para economizar tempo).


A visibilidade aproximada da câmera é sobreposta à imagem. A largura deste triângulo depende do campo de visão - às vezes nos jogos, é uma opção personalizada, às vezes um valor constante.


Aqui está uma exibição em wireframe da cena, o campo de visão da câmera é limitado ao branco.



Alguns de vocês já poderiam pensar em um pequeno truque que permitiria contornar a restrição de renderizar um certo número de objetos - por que não fazer dos objetos uma combinação muito complexa de tudo em uma pequena área, até folhas individuais? Então desenhar 1000 objetos será mais que suficiente.

Mas aqui estamos diante de um conjunto completamente diferente de restrições - as placas gráficas têm desempenho limitado e quanto mais complexo o objeto, mais tempo será necessário para desenhar. Ou seja, mesmo um objeto, se for bastante complexo, pode reduzir a taxa de quadros do jogo para 20 FPS. Incluindo foi por isso que eu disse que o limite no número de objetos é bastante confuso.

A quantidade de tempo gasto em um objeto depende da complexidade e detalhes dos modelos e texturas, bem como da sofisticação da iluminação e das sombras. É também por isso que os jogos que tentam implementar gráficos mais complexos ou sofisticados tendem a usar cenas menos complexas e detalhadas - o balanceamento muda as escalas em uma direção ou outra, para que você possa ter mais espaço de manobra, sacrificando o que não é tão importante para o jogo. .


Esse é um tipo de mapa de calor, mostrando em quais partes da cena existem modelos especialmente complexos. Observe quantos problemas as árvores e a vegetação podem causar.

Há outro conjunto de técnicas chamado "nível de detalhe" (LOD), projetado especificamente para resolver esses problemas. Semelhante ao fato de podermos otimizar o número de objetos, cortando tudo o que é desnecessário, podemos aumentar a oferta de "complexidade", eliminando o desnecessário.

Um dos truques é realmente bem conhecido - isso está mudando a resolução das texturas. Esse tópico geralmente se cruza com muitos outros, então tentarei explicá-lo de uma maneira acessível.

As texturas nos jogos geralmente são retângulos com tamanhos iguais à potência de dois - 512, 1024, 2048, 4096. Há muitas razões para isso, mas uma das vantagens disso é que você pode pegar uma textura de tamanho 1024x1024 e criar facilmente uma versão menor com tamanho de 512x512 .

Pelas razões que irei discutir abaixo, é sempre necessário que a textura tenha todos os tipos de versões menores. Ou seja, uma textura com um tamanho de 1024x1024 terá versões menores de 512x512, 256x256, 128x128, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2 e 1x1. No entanto, uma das vantagens disso é que, se objetos distantes tiverem um tamanho pequeno na tela, aplicar uma textura 1024x1024 a eles significa desperdiçar recursos. Podemos economizar usando versões menores da mesma textura.

Da mesma forma, mesmo objetos próximos podem ser considerados não muito significativos e usar texturas menores para eles.

Nota


Geralmente, quando um jogador se aproxima de um objeto, a maior textura é usada, mas como a maioria das pessoas já viu em um jogo em particular, isso nem sempre acontece e as texturas parecem muito embaçadas antes do carregamento. Isso geralmente acontece porque as texturas não podem ser carregadas de um DVD ou disco rígido diretamente na memória da placa gráfica para renderização. Na maioria das vezes isso acontece quando um jogador muda abruptamente de posição, por exemplo, durante o reaparecimento, carregando um novo nível ou um movimento muito rápido. Em todos os outros casos, as texturas geralmente são carregadas gradualmente, no processo de mover o jogador ao redor do mundo.

Você também pode aplicar esse processo de simplificação aos modelos usados ​​no jogo, embora seja muito mais difícil de fazer. Ao criar versões simplificadas de objetos complexos, você pode garantir que a uma grande distância eles não corroem parte de um suprimento limitado de complexidade.

Graças a objetos simplificados e modelos cortados, você pode economizar muito dinheiro e usar essa abordagem em qualquer jogo como o Watch Dogs. Mas, ao mesmo tempo, pode ser um enorme desperdício de recursos. É necessário tomar uma decisão muito ponderada e equilibrada sobre quantas versões simplificadas de modelos são necessárias. Se houver muito poucos deles, você não poderá economizar muito, ou haverá saltos visíveis na qualidade ao alterá-los. Se houver muitos deles, você desperdiçará memória e gastará as horas necessárias para criar objetos.


É assim que objetos e personagens complexos parecem distantes quando são indistinguíveis de suas versões altamente detalhadas.



Espero que agora você tenha uma idéia dos problemas que programadores gráficos, artistas e designers de nível estão tentando combinar com gráficos de alta qualidade e alta velocidade. Nos consoles, essa equação é um pouco mais fácil de resolver do que no PC, porque o equipamento é constante.

Na parte anterior, eu disse que falarei sobre por que é muito difícil implementar corretamente reflexões e outras coisas semelhantes. O motivo é bem simples: as reservas de produtividade e recursos de que falo constantemente não mudam, dependendo de você refletir ou não. Se você quiser criar uma reflexão que possa exibir novamente toda a cena, precisará refazer todo o trabalho que eu falei. Além disso, as reflexões dependem muito do ângulo em que as olhamos; portanto, para obter reflexões precisas para cada objeto refletido, elas devem ser suas!

Isso pode sair do controle muito rapidamente e, geralmente, jogos nos quais há reflexões permitem certas liberdades ou suposições. Os jogos raramente criam reflexos em ambientes complexos, o máximo que pode ser é um espelho no banheiro, onde não há tantos objetos, a complexidade da cena é pequena e, portanto, você pode arcar com despesas extras. Talvez os verdadeiros reflexos no jogo estejam apenas em superfícies irregulares ou onduladas da água, de modo que mesmo uma cena muito áspera e pouco detalhada seja suficiente para criar reflexos convincentes.

Geralmente é difícil evitar completamente superfícies refletivas, e é por isso que os jogos usam imagens pré-renderizadas do ambiente imediato, o que resulta em um resultado "razoavelmente bom". Mas eles não são minuciosamente escrutinados e, se você observar atentamente as reflexões, verá que isso é uma imitação. Existem técnicas modernas que ajudam a criar reflexões em determinadas condições, e talvez mais tarde eu fale sobre elas, mas essas imagens pré-renderizadas ("pré-renderizadas") ainda são necessárias.


Essa imagem renderizada é chamada de "mapa de cubo". Não é totalmente preciso em relação ao local onde Aiden está, mas está perto o suficiente dele.

Watch Dogs processa reflexões em tempo real. Não investiguei esse assunto em detalhes, mas acredito que eles sempre são exibidos quando o personagem está na rua e são usados ​​principalmente para obter suas reflexões exatas sobre o carro em que ele está sentado, para melhorar a imagem e dar a ele um leve senso de realidade. . Como o jogador está sempre focado no carro e no ambiente imediato, o fato de refletir incorretamente em outros carros é quase imperceptível.

Existem muitas aproximações disponíveis para acelerar a renderização dessas reflexões. Por exemplo, muito menos objetos são renderizados na reflexão do que na cena real - cerca de 350 no total - e muitos deles são muito simplificados em comparação com as versões completas. Suspeito que objetos complexos, como pessoas, sejam completamente descartados, independentemente da distância, mas não testei essa teoria. Além disso, não há sombras nesses objetos e a iluminação é muito simples - apenas a que vem do sol e do céu. Os reflexos são renderizados a partir do solo como em uma lente “olho de peixe”, ou seja, os reflexos da própria terra são impossíveis, e o que está ao lado tem detalhes muito baixos.

Mas, mesmo com todas essas simplificações, as reflexões lidam apenas com o que se pretendia. Se você dirige por baixo dos trilhos, pode obter o reflexo certo com uma visão sobre o carro, o que, na prática, não funcionaria.

Esta decisão foi intencional e não fácil de tomar. O estoque é um valor constante; portanto, se você deixar espaço para essas reflexões, precisará sacrificar outra coisa.


Aqui está uma visão muito "desconfiada" da cena em torno de Aiden com uma vista inferior, feita para reflexões. Você pode navegar pelas duas luzes e trilhos do trem.



Há outra parte do trabalho que quero mencionar aqui - sombras. Mais tarde, pretendo falar sobre como as sombras funcionam, porque esse é um tópico interessante, mas agora o mais importante é lembrar que as sombras são muito semelhantes às reflexões. Cada fonte de luz que projeta uma sombra deve renderizar uma imagem de cena do seu ponto de vista. Desta vez, não há muitas maneiras de simplificar o trabalho - para o cálculo correto das sombras, cada fonte de luz deve ter essa imagem.

Nota


, . , «» , . , , .

A fonte mais óbvia e significativa de iluminação que dá sombra é o sol (ou a lua, se a coisa acontecer à noite). Como o sol é imenso, geralmente são renderizadas de 3 a 5 imagens, e não uma, como no caso de faróis ou lanterna.

Infelizmente, este é um dos casos em que o Watch Dogs não pode servir como um bom exemplo. O cálculo das sombras no jogo é bastante complicado e, ao que me parece, é especialmente otimizado para o caso de projetar sombras na cidade. Portanto, é melhor mudar para Far Cry 4 e considerar o cálculo das sombras no exemplo de um quadro deste jogo.


Aqui está uma cena do Far Cry 4 que estou usando como exemplo.


Aqui está uma imagem com informações sobre as sombras dessa cena - cada uma delas requer uma renderização completamente nova da cena.

Portanto, quando precisarmos adicionar projeção de sombra à fonte de luz, teremos que renderizar a cena mais uma vez. Aqui, você também pode usar algumas das aproximações usadas no caso de reflexões, apenas elas são muito menores. Você pode pular objetos pequenos ou distantes, mas lembre-se de que esses objetos não parecerão projetar sombras. Você pode renderizar a imagem muito pequena, mas as sombras ficarão granuladas e com poucos detalhes. Geralmente, não é possível usar uma versão muito simplificada do objeto, porque parece que o objeto lança uma sombra sobre si mesmo ou aparecem lacunas entre o objeto e sua sombra.

Outra consequência que é muito fácil de perder é a necessidade de criar imagens sombreadas para cada fonte de luz. Em muitos casos, é possível simplificar as fontes de iluminação combinando-as - no Watch Dogs isso acontece com os faróis dos carros.

Quando as duas luzes estão acesas, apenas uma fonte de luz é desenhada, mas possui uma forma especial, por causa da qual se parece com dois raios. Se os faróis tiverem sombras, isso não é fácil, e será muito mais notável - quando o jogador passa na frente do carro, a luz virá de algum lugar entre os dois faróis. Talvez você precise separar os faróis, mas, ao mesmo tempo, não apenas haverá custos adicionais para calcular as sombras, mas também precisará desenhar uma nova iluminação.



A principal coisa que eu queria enfatizar com tudo isso era compromisso. Certamente podemos nos livrar de todas essas aproximações, mas teremos que gastar nossas reservas de recursos nisso, ou seja, sacrificar outra coisa. Cada desenvolvedor de jogos deve decidir o que é importante para ele se concentrar no jogo e o que mais impressionará ou incomodará o jogador.

Parte 4. Movendo os picos


Nesta parte, falarei mais sobre os detalhes técnicos da animação de objetos na cena.

Programadores gráficos frequentemente falam sobre o "pipeline gráfico". Os gráficos 3D são um pouco como uma linha de montagem com um movimento claramente definido de um estágio para outro, mas não funcionam apenas com um objeto por vez.

Todas as placas gráficas modernas possuem aproximadamente a mesma correia transportadora, possuem equipamento e software especiais que são diretamente “silicados” para maximizar a velocidade do transportador. Obviamente, existem muitas variações entre diferentes fabricantes e famílias de placas gráficas, mas geralmente não precisamos nos preocupar com como elas funcionam nesse nível.

Nota


Se você estiver interessado em saber como tudo funciona em um nível de hardware abstrato, recomendo uma série de artigos de Fabian Giesen no pipeline de gráficos . Esta série de artigos é muito mais detalhada e requer muito mais entendimento do que meu post.

Vou pular muitos detalhes para explicar princípios interessantes e importantes. Nesta parte, veremos a primeira parte do pipeline, chamada de Vertex Shader .

Os shaders se espalharam há cerca de 16 anos, após o lançamento do DirectX 9, no qual os shaders de vértice e pixel apareceram. Para explicar o que são shaders e compará-los com o que costumavam ser, falarei sobre o trabalho que eles fazem.


A cabeça esquelética de Aiden está conosco novamente.

Deixe-me lembrá-lo que, na parte 2, examinamos os modelos a partir dos quais o mundo do jogo é criado. Esses padrões são compostos de pontos individuais chamados vértices, conectados em triângulos. Eu disse que falarei mais sobre eles mais tarde e agora cumpro minha promessa.

Como tudo no mundo do jogo consiste em vértices, tudo o que precisa ser feito com esses modelos deve ser realizado com vértices. Quando se trata da placa de vídeo, tudo o que vê é uma longa lista de vértices. Para ela, não existem coisas como animações em execução, folhas balançantes de árvores ou quaisquer outros conceitos abstratos.

Vejamos um exemplo simples do que temos que fazer - mover e posicionar objetos no mundo. Para começar, vamos considerar um caso simples, não um personagem.

Ao criar objetos em editores 3D como Maya e 3D Studio Max, os artistas sempre constroem em seu próprio mundo separado. Esses objetos não são criados imediatamente na comitiva de Chicago; seus arredores parecem uma "sala branca vazia" da Matrix. Cada objeto está localizado no centro do vazio absoluto.


Aqui está um semáforo no jogo em algum lugar sob os trilhos, e ele está localizado em seu próprio mundo.

Ao salvar em disco, o modelo não faz ideia de onde estará no mundo e quando será baixado e transferido para a placa gráfica. Isso significa que, quando chega a hora de desenhar objetos, precisamos movê-lo de nosso próprio mundo para a cena que desenhamos. Isso acontece com todos os objetos desenhados, e mesmo objetos imóveis como edifícios e pontes também se movem do próprio mundo para a cena em cada quadro.


Aqui vemos vários semáforos já colocados em uma cena final parcialmente construída.

Como mencionei acima, as únicas coisas com as quais podemos trabalhar são os picos. Não podemos dizer apenas para a placa gráfica: "Você pode colocar esse semáforo embaixo da ponte? E depois colocar outro um pouco mais? Ótimo!

Portanto, em vez de dizer à placa gráfica o que ela precisa fazer com o próprio objeto, precisamos dizer o que fazer com todos os seus vértices. Acontece que, neste caso, tudo se torna muito simples. Se mudarmos todos os vértices exatamente da mesma maneira e eles permanecerem imóveis em relação um ao outro, isso é semelhante a mover um objeto como um todo. Tudo o que precisamos fazer é descobrir o que "mudança" é chamado de transformação.

Nota


Os cálculos matemáticos de tudo isso não são particularmente complicados, mas estão além do escopo do artigo. Se você já estudou álgebra linear, provavelmente sabe tudo o que precisa - basicamente tudo se resume à multiplicação matricial de vetores.

Antes do aparecimento dos shaders de vértice, as opções possíveis para transformar vértices na placa de vídeo eram muito limitadas. Havia objetos em movimento e em rotação, além de outras operações, mas nada particularmente redundante ou complicado.

Os vertex shaders são pequenos programas de computador que são executados em uma placa gráfica. Eles pegam um vértice, executam as ações necessárias e emitem um vértice de saída. Eles podem não apenas movê-lo, mas também fazê-los pular para cima e para baixo, afastar-se do pico mais próximo, balançar dependendo do vento, ser animados e muito mais.

Peguei um dos shaders de vértice usados ​​no Watch Dogs e experimentei um pouco para mostrar o que ele faz. Este é um trabalho minucioso, mas consegui encontrar o shader de vértice usado para os personagens e alterá-lo. Há outro sombreador de vértice usado para a pele, por exemplo, para rostos e mãos, mas você entenderá rapidamente o princípio.


Fiz uma alteração muito simples que adiciona uma curva ao modelo de personagem, mas todo o resto é usado como de costume.

A animação acima mostra que os personagens estão de alguma forma estranhamente distorcidos. Isso nos leva de volta ao princípio "se você mover cada vértice, será semelhante a mover o objeto inteiro". A alteração feita no sombreador de vértice funciona apenas para um vértice de cada vez, mas como todos funcionam com a mesma distorção, o efeito é aplicado a todo o objeto.

Você também pode fazer alterações na parte da transformação, responsável por “simplesmente se mudar para o lugar”, de modo que, em vez de colocar o personagem no lugar certo, ela o levante acima do solo. Isso não é simulado com a ajuda da física, portanto, não tem nada a ver com a gravidade ou colisões com outros objetos - se quisermos, podemos fazer com que todos voem no ar.


Nesta animação, fizemos o sombreador de vértice aumentar e diminuir gradualmente o objeto.

Obviamente, tudo isso não é muito construtivo, mas nos dá uma idéia geral de como os shaders de vértice funcionam - se agora quiséssemos animar as folhas das árvores para que elas balançassem, faríamos o mesmo. Somente em vez de levantar e abaixar eles balançariam na direção do vento. Então podemos mudar a força do vento para que as árvores balançem mais ou menos.


Aqui vemos o que acontece quando tudo aumenta cerca de sete vezes.

Simplifico um pouco, mas basicamente a tarefa da maioria dos shaders de vértice é "mover objetos no lugar". A exceção são todos os objetos animados - pessoas, animais e objetos como cordas balançando, roupas esvoaçantes etc.



Animar as pessoas está ligado à idéia de usar um esqueleto e uma "pele". Um esqueleto é uma descrição simples de um personagem em movimento. Nesta fase, não estamos preocupados com fivelas, chapéus ou jeans que não são animados - apenas movimentos importantes que são mais apropriados para o esqueleto humano são importantes para nós.


Um esqueleto simples de uma figura humana é mostrado aqui. Não foi tirado do Watch Dogs, porque é difícil visualizar o esqueleto fora do editor 3D.

Imagem licenciada pela Atribuição-Compartilhamento pela mesma licença CC BY-SA © equipe MakeHuman 2001-2014


Essa é uma pose instantânea ou pose em T que demonstra a aparência de um personagem sem usar animações.

As animações - correr, andar, pular - se aplicam apenas a esse esqueleto. Isso torna todo o processo muito simples, porque precisamos considerar apenas cerca de cem ossos em vez de milhares e milhares de vértices.

Depois de criar o esqueleto, cada vértice é anexado a um ou mais ossos nessa pose estática, e essa conexão é chamada de "esfola". Na época do Half-Life 1, quando essa tecnologia começou a ser usada, cada vértice se associava a apenas um osso. Atualmente, eles podem unir quatro ossos, enquanto cada osso recebe peso, do qual depende o grau de influência do osso no ápice. Graças a isso, você pode obter uma animação mais suave, permitindo que os ossos se cruzem em diferentes áreas sem criar ângulos agudos ao mover braços ou pernas.


Este é o esqueleto mostrado acima com o osso da coxa virado. As cores mostram o peso do osso do quadril em relação às partes superiores do modelo.

Imagem licenciada pela Atribuição-Compartilhamento pela mesma licença CC BY-SA © equipe MakeHuman 2001-2014

Essa tecnologia tem suas limitações, especialmente em locais onde roupas e pele são comprimidas ou esticadas em dobradiças, por exemplo, nos cotovelos e ombros. Esta é uma maneira imperfeita, mas muito eficaz de animar. A limitação mais séria é que é muito difícil criar animações de rosto atraentes dessa maneira. Você pode criar muitos ossos "falsos" no rosto, por exemplo, nas sobrancelhas e ao redor da boca, mas isso será apenas uma aproximação aproximada dos músculos e da pele.

Outra característica importante dessa técnica é que a comparação de vértices e ossos é muito específica e está relacionada à forma como essa comparação é realizada. É possível usar animações para vários modelos diferentes, mas cada modelo individual no qual você deseja usar o esqueleto deve estar associado aos ossos. O motivo é que as animações movem os vértices de sua posição original em relação aos seus esqueletos. Se os vértices não estiverem nas posições esperadas, surgirão problemas.


Se o modelo não corresponder ao esqueleto usado por ela, as animações estarão completamente incorretas.


Se tornarmos o personagem duas vezes mais largo, obteremos um efeito semelhante aos "donuts excessivos" de Drake , mas é perceptível que as animações mais próximas aos pincéis se tornam incorretas, porque é aqui que elas estão mais afastadas de suas posições originais.

A primeira animação pode parecer estranha para você - essas animações de falha ocorrem nos jogos com muita frequência. Geralmente, elas são causadas pelo fato de animações incorretas serem aplicadas ao esqueleto ou pelo modelo usar o esqueleto errado. Como no caso de texturas e modelos, o esqueleto, a aparência e o modelo devem ser comparados com muito cuidado, caso contrário, os resultados rapidamente se tornarão tristes.

Espero que você tenha uma idéia do objetivo dos shaders de vértice e entenda como as animações são usadas para transformar um modelo estático em um personagem vivo.

Source: https://habr.com/ru/post/pt430930/


All Articles