Shaders escritos em OSL

Finalmente descobri o que estava fazendo a imagem ser renderizada de maneira errada, conforme mencionado no post anterior. Tenho até vergonha de admitir, mas eu estava usando a versão antiga do shader que modela vidro.

Implementação de um novo shader

Um dos shaders mais simples que existe é o que modela uma superfície perfeitamente áspera, ou seja, só tem reflexão difusa. A descrição em OSL de uma tal superfície é dada por:

surface yellow () {
    Ci = color(1.0, 1.0, 0)*diffuse(N);
}

Apliquei esse shader na esfera da direita, resultando na seguinte imagem:

Grupos de Shaders

Para testar o grupo de shaders, criei 3 shaders iguais ao yellow.osl, mas com as cores vermelha, verde e azul, chamando-os de red.osl, green.osl e blue.osl, respectivamente. Também criei um shader chamado blender.osl, que recebe como parâmetro três cores closure e faz uma média delas:

surface blender (
	closure color r = diffuse(N),
	closure color g = diffuse(N),
	closure color b = diffuse(N)){
	Ci = r*(1.0/3) + g*(1.0/3) + b*(1.0/3);
}

Na hora de criar o shader group, declarei cada shader e conectei a saída da cores no blender. Diferentemente da especificação, a implementação do sistema de shaders atual do OSL, ao criar um shader, passamos como parâmetro o uso do shader (superfície, deslocamento, etc.), o nome do shader e o nome do layer. A ligação é feita conforme a especificação:

shadingsys->ShaderGroupBegin();
// Declaracao dos shader layers
shadingsys->Shader("surface", "red", "red1");
shadingsys->Shader("surface", "green", "green1");
shadingsys->Shader("surface", "blue", "blue1");
shadingsys->Shader("surface", "blender", "blender1");
// Ligação entre os shaders
shadingsys->ConnectShaders("red1", "Cout", "blender1", "r");
shadingsys->ConnectShaders("green1", "Cout", "blender1", "g");
shadingsys->ConnectShaders("blue1", "Cout", "blender1", "b");
shadingsys->ShaderGroupEnd();

Pelo meu entendimento, o closure resultante seria igual a (1.0/3, 1.0/3, 1.0/3), pois está fazendo a média entre vermelho (1,0,0), verde (0,1,0) e azul (0,0,1), ou seja, a cor seria cinza.

Aplicando na mesma esfera da direita, qual não foi minha surpresa ao vê-la com a cor marrom:

Revisei o código do raytracer e entendi direito o funcionamento. Não é que se calcula a cor resultante a partir das operações do closure. O que se faz é ir descendo na árvore de expressões e calculando a cor. Ao chegar em uma folha, teremos uma dada cor. Se por acaso a primitiva correspondente for escolhida, assim também será a cor.

No exemplo, começa-se a avaliação da árvore com w = (1, 1, 1). Ao descer para a folha de alguma das primitivas, multiplicamos w por 1.0/3, então temos (1.0/3, 1.0/3, 1.0/3). Se a primitiva no shader red.osl for escolhida, por exemplo, multiplicamos ainda por (1.0, 0, 0), resultando em (1.0/3, 0, 0).

Isso significa que na prática, o closure resultante retorna vermelho, verde ou azul com igual probabilidade. Se olharmos a imagem amplificada, dá pra ver que a esfera é composta por vários pixels vermelhos, verdes e azuis misturados.

Próximos passos

Com isso acho que cumpri as tarefas para o período antes do começo do projeto (fase do community bounding). Deixando um pouco o OSL de lado e voltando ao BRL-CAD, as próximas tarefas para serem cumpridas nas próximas duas semanas são:

  • Implementar um shader novo para o BRL-CAD (sugestões incluem texturas de zebra ou de pontos-polka).
  • Atribuir a um objeto e renderizar.

Os comentários estão fechados.

%d bloggers like this: