As pessoas costumam me perguntar em que projeto devem trabalhar para aprender a programar. Eu sempre respondo da mesma forma. Escreva um raytracer. Eu não digo isso apenas para as pessoas que desejam aprender programação gráfica especificamente, eu digo isso para todos que desejam aprender programação geral também.

Existem muitas razões pelas quais raytracers são uma boa maneira de aprender a programar, mas aqui estão cinco:

É muito fácil. Não há nada particularmente difícil sobre a criação de sites baratos. Se você tem experiência em programação e matemática de nível médio, pode começar a criar imagens bonitas com código puro. Então, o que você está esperando?

Curva de aprendizado superficial. Primeiro, obtenha os pixels plotados em uma imagem. Em seguida, faça uma classe vetorial funcionar. Em seguida, cruze um raio com uma esfera. Em seguida, calcule os normais. Em seguida, calcule a iluminação. Em seguida, sombras, texturas, reflexo, suavização e assim por diante. Cada etapa é independente, simples de entender e fácil de adicionar.

Depuração visual. Você pode ver se seus normais estão invertidos. Você pode ver se suas sombras precisam de um épsilon maior. Você pode ver se os raios da câmera estão distribuídos de maneira não uniforme. Somos criaturas visuais e ser capaz de ver qualquer problema é muito mais fácil do que se você estiver depurando um sistema de dados abstrato.

Ele se encaixa bem com paradigmas de programação. Independentemente de qual linguagem você deseja aprender, ou com qual metodologia você trabalha, o raytracing ensina muito sobre algoritmos e estruturas de dados. É divertido resolver quebra-cabeças em qualquer idioma. Programação orientada a objetos vs programação funcional, octree vs kd-tree, GPU vs CPU multithread. Você pode fazer do seu jeito e conseguir o que quiser.

Resultados bonitos. Você pode adicionar fotos bonitas ao seu portfólio e dizer: “Eu escrevi o programa para gerá-las”. Ao procurar um emprego, é mais fácil impressionar entrevistadores menos técnicos com suas imagens e animações do que com uma descrição seca de um sistema de banco de dados.

criação de sites baratos

Outro conselho que tenho para as pessoas que estão aprendendo a codificar é encontrar algum código horrendo e ofuscado e desmontá-lo. Um ótimo recurso para isso é o Concurso Internacional de Código C Ofuscado. Tem alguns exemplos maravilhosos de código totalmente incompreensível. O que é ótimo nisso é que eles geralmente são muito curtos, então não é como se você estivesse tentando decifrar uma base de código gigante. Pegue um que pareça interessante, faça um novo projeto e comece a compilar. Em seguida, embeleze o código. Adicione espaços em branco e colchetes, altere nomes de variáveis ​​e funções para torná-los mais significativos e reduza macros obscuras. Eu não posso te dizer o quanto aprendi e melhorei como programador fazendo isso.

Para este artigo, eu escrevi um programa de raytracing bastante mínimo que você pode desempacotar. O código é ofuscado o suficiente para que você gaste um pouco de tempo organizando-o para ver como funciona – é assim que você aprenderá -, mas estruturado o suficiente para que você possa ver as partes do programa com facilidade. Eu adoro espremer código para que ocupe o mínimo de espaço. Existe algo de belo no código feio que faz coisas legais.

Enfim, aqui está a imagem que iremos gerar:

Não é nada especial, mas é totalmente gerado pelas 55 linhas de código C ++ abaixo.

Aqui está uma explicação detalhada do código como uma lista com marcadores. Não está em uma ordem linear, está em uma ordem mais compreensível, começando com a estrutura de alto nível até os detalhes.

A linha 49 é o ponto de entrada principal. Geramos a imagem cuspindo o conteúdo de um formato de arquivo de imagem baseado em texto. Você pode transformá-lo em uma imagem copiando a saída para um arquivo de texto e salvando-o com a extensão .ppm. No Linux ou Mac, apenas executo o programa compilado e canalizo a saída para um arquivo como este: ./ minimalraytracer> output.ppm

A linha 50 é o cabeçalho do arquivo de imagem ppm. Começa com “P3”, passa a ter a largura e altura da imagem (definidas na linha 4), depois um valor que denota a escala dos componentes, neste caso, 255.

A linha 51 é, na verdade, um loop aninhado sobre a imagem inteira, formatado para se parecer com um único loop para economizar espaço.

A linha 53 é onde escrevemos os componentes vermelho, verde e azul para cada pixel na saída. Fixamos cada componente em 1, multiplicamos por 255 e, em seguida, convertemos em um inteiro.

A linha 52 chama a função “trace”, que retorna a cor para aquele pixel. Ele é retornado como um vetor 3D.

As linhas 5 a 15 definem a classe de vetor 3D mínima chamada “v”. Eu uso um struct simplesmente porque é uma classe com dados e métodos públicos e, portanto, me economiza escrevendo “public:”

A linha 6 mostra que o vetor tem apenas três flutuadores, x, y e z.

A linha 7 é o construtor.

a linha 8 é um método que retorna o comprimento do vetor.

A linha 9 retorna um vetor unitário na mesma direção.

As linhas 10 a 13 são operadores sobrecarregados, permitindo uma manipulação vetorial mais fácil.

A linha 14 é um método estático que retorna o produto escalar de dois vetores.

A linha 30 é o início da função de rastreamento. Ele pega um raio como entrada e retorna a cor que o raio pode “ver” no mundo que definimos. O é a origem do raio, D é a direção normalizada do raio. Finalmente, a função chamará a si mesma para refletir os raios de reflexão, então RD (Profundidade recursiva) é o número de rebatidas que permitimos.

A linha 31 contém as variáveis ​​locais. h é o índice da esfera que o raio atinge, onde menos um significa que não atingiu nada. T maiúsculo é um float temporário que usaremos e t minúsculo rastreia a distância mais próxima ao longo do raio que atingiu um objeto. Precisamos disso para encontrar a esfera mais próxima.

A linha 32 chama a função “intersectar” para cada esfera e registra a mais próxima que o raio atingiu.

As linhas 21 a 29 são a função de “interseção”. É necessária uma referência a uma esfera, a origem e direção do raio e uma referência a um flutuador para definir a distância do ponto de interseção. A função retorna true se houver uma interseção, embora eu use um número inteiro em vez de um booleano para economizar espaço. Não vou explicar o código para esta função, mas você pode encontrar mais informações sobre interseções de linha / esfera aqui.

A linha 33 é onde testamos para ver se o raio cruzou com uma esfera ou não. Se h não for mais -1, significa que atingimos uma esfera e podemos calcular a cor, que retornamos na linha 45.

Linha 47: Se nenhuma interseção ocorreu, retorna a cor do céu, que é um gradiente baseado na inclinação vertical do raio.

A linha 34 é onde começamos o cálculo da cor com base na esfera interceptada. Calculamos o ponto de intersecção, a normalidade da esfera nesse ponto, um raio de reflexão refletido na esfera e a cor se não houvesse luzes.

A linha 35 é um hack completo. Se o índice da esfera for 0, significa que o raio atingiu a grande esfera branca que uso como base. Nesse caso, use os componentes x e z para fazer uma textura quadriculada.

criação de sites baratos

As linhas 36 a 43 são onde adicionamos contribuições de cor das luzes na cena.

A linha 38 é onde testamos um raio de sombra com a geometria da cena para ver se o ponto está na sombra daquela luz em particular.

Linha 40: se o ponto não está escondido da luz, calcule as contribuições difusa e especular da luz.

A linha 41 é onde acumulamos a luz.

A linha 44 é onde também acumulamos recursivamente a luz refletida na superfície, até o limite recursivo.

E aí temos que. Esse é um raytracer básico que cria uma imagem simples, mas atraente de algumas esferas.

Aqui estão algumas idéias do que você pode fazer para melhorá-lo.

Antialiasing. Fazer a média de um monte de raios jittered para cada pixel dará um resultado muito mais suave, sem jaggies nítidos.

Profundidade de campo. Quando o anti-serrilhamento é feito, se você agitar os raios de forma que eles convergem em um plano na frente da câmera, você pode obter um efeito embaçado próximo e distante com um plano focal nítido no meio. Isso realmente aumenta o realismo.

Sombras suaves. Se você calcula a média das amostras alterando a posição das fontes de luz dentro de uma esfera, pode tornar as bordas das sombras suaves, o que parece muito bom.

Câmera. Use uma matriz para transformar os raios depois de criá-los para que você possa mover e girar a câmera para composições mais artísticas.

Texturas. O padrão xadrez é um hack completo. Tente carregar imagens e usá-las para cores de objetos.

Melhores materiais. Este programa simples usa o modelo de sombreamento Phong e não tem como especificando refletividade, brilho ou qualquer outro parâmetro de material. Experimente diferentes modelos de sombreamento.

Mais formas. As esferas são muito fáceis de se cruzar, mas você também pode cruzar planos, cones, cilindros, caixas e, se estiver se sentindo corajoso, toróides.

Malhas triangulares. Isso realmente abrirá o raytracer. Carregue uma malha de triângulo e cruze os polígonos com o raio. Sempre comece com o Stanford Bunny.

então o que você acha? Você aprendeu alguma coisa com este exercício? Você adicionou novos recursos e criou suas próprias imagens? Eu adoraria vê-los. Você encontrou algum bug no código? Você encontrou maneiras de otimizá-lo?

Depois de começar a criar um raytracer, você rapidamente se encontrará caindo em uma toca de coelho de programação gráfica. No entanto, é uma descida tranquila e você aprenderá e se divertirá durante toda a descida.