Image Based Cartoon Style Rendering Jeronimo Silvério Venetillo Fabio Issao Nakamura O que é Cartoon Render? • É uma uma forma de renderização não fotorealística. • Não é baseada nas leis físicas de iluminação, mas sim na percepção humana. • Tenta realçar detalhes do modelo, visando entendimento e não fidelidade. Características • Realce de silhuetas. • Realce de arestas. • Poucos tons. Silhueta • Delimita o modelo • É o conjunto de arestas que formam o contorno de um modelo, dado um observador. Arestas • Mostra as quinas do modelo. • É o conjunto de arestas que compartilham duas faces em que suas normais possuem um angulo maior/menor que um determinado valor de referencia. Tons • Normalmente apenas dois tons são usados. • Não traz a noção de profundidade que a iluminação de phong nos dá. • Esta percepção é dada pela silhueta e/ou arestas do modelo. • Um dos tons simula a parte iluminada e o outro a parte “em sombra”. • Com isso, a cor do material é preservada na integra e a parte não iluminada é apenas um tom mais escuro desta cor. • Temos uma divisão melhor de o que está sendo iluminado e o que não está sendo iluminado. Tons Como Fazer? • Usando Geometria e API Padrão • Usando Geometria e Programação em Placa (Vertex Shader). • Usando Processamento de Imagem e API Padrão. • Usando Processamento de Imagem e Programação em Placa (Pixel Shader). Opção 1 • API convencional • Independente de plataforma. • Maquinas Silicon Graphics não tem GPU programável. Opção 2 • Processamento de Imagem • “Não dependede” da geometria usada. • Não tem a necessidade de desenhar linhas. Método Cor Ambiente e Silhueta • Renderizar cena vista da posição da camera com as luzes desligadas. Cada objeto tem sua cor ou textura afetado apenas pela iluminação ambiente. • Com esta renderização, obtemos dois buffers. O ambientBuffer e o Z-Buffer. • Aplicamos um filtro de detecção de descontinuidade no Z-Buffer para obtermos as silhuetas dos modelos (silhuetteBuffer). Filtro ( Parte 1 ) • O filtro usado para detecção de descontinuidade foi o filtro de Sobel. Filtro ( Parte 2 ) • Este operador produz um gradiente do Z-Buffer. • As silhuetas são as áreas que possuem um gradiente alto. • Para extrair estas áreas, usamos o seguinte filtro não linear: p = min{ [(gmax – gmin )/kp]^2, 1 } Onde gmax e gmin são os valores máximos e mínimos da vizinhança 3x3 considerada. • O parâmetro kp é o limiar de detecção e está entre 0 e 1. Quanto menor kp, mais silhuetas serão consideradas. Método Arestas • Teoricamente a aplicação de um filtro de segunda ordem no Z-buffer nos dá as arestas. • Na pratica, esse resultado se mostra muito instável por problemas de aproximação. • Podemos aplicar o mesmo filtro que aplicamos no Z-Buffer se tivessemos um mapa de normais da cena. Mapa de Normais • Podemos criar um mapa de normais da cena!! • Usamos a cor de cada pixel para guardar o valor da normal naquele pixel ( rgb -> xyz ) • Substituimos as cores e texturas de todos os objetos por um material totalmente difuso e branco ( corAmbiente = preto, corDifusa = branco, sem Especular ) • Desligamos as fontes de luz. Mapa de Normais • Fazemos uma passada de render ligando três luzes direcionais, gerando normalBuffer1. – Uma vermelha, na direção x – Uma Verde, na direção y – Uma Azul, na direção z • Cada pixel que tem a normal (nx, ny, nz), terá a cor ( max(nx, 0), max(ny, 0), max(nz, 0) ) • Fazemos outra passada de render, invertendo a direção das luzes , gerando normalBuffer2. – Vermelha na direção –x – Verde na direção –y – Azul na direção -z Mapa de Normais • Precisamos agora fazer: normalBuffer = normalBuffer1 – normalBuffer2 y z x Arestas • Aplicamos agora o mesmo procedimento utilizado no Z-Buffer no normalBuffer para obtermos as arestas (creaseBuffer). Linhas de Realce • Temos agora dois buffers que mostram todas as linhas que devem aparecer na imagem final. • Para criarmos um único buffer, multiplicamos os dois anteriores. • lineBuffer = silhuetteBuffer * creaseBuffer Método Tons • Calculamos os tons da imagem a partir do normalBuffer e do • • ambientBuffer. Usamos o produto escalar da posição da luz com o valor da normal no pixel. Caso ( Plight dot normalBuffer[p] ) > 0 iluminatedBuffer[p] = ambientBuffer[p] * LightColor Caso contrário iluminatedBuffer[p] = ambientBuffer[p] Para cada luz a mais Caso ( Plight dot normalBuffer[p] ) > 0 iluminatedBuffer[p] += ambientBuffer[p] * LightColor Caso contrário iluminatedBuffer[p] += ambientBuffer[p] repeat Normalmente apenas uma luz é utilizada. Imagem Final • Para gerar a imagem final, multiplicamos o iluminatedBuffer pelo lineBuffer. • finalBuffer = iluminatedBuffer*lineBuffer Método Resultados e Conclusões • Esse método utiliza muito a comunicação entre a placa gráfica e a CPU, o que geralmente é feito de maneira muito lenta. • Por causa disso, taxas para tempo real estão longe de serem alcançadas. • Porém, alcançamos facilmente taxas iterativas, o que nos permite fazer visualização e inspeção de modelos. Resultados e Conclusões • O resultado visual se mostra muito bom diante do proposto. • Realmente o realce de detalhes fica bem evidente. Demo • Cartoon.exe