Ao escrever um shader que precisava da leitura de algumas texturas. Percebi a quantidade de pequenas coisas que temos de lembrar quando utilizamos arquivos de textura em nossos shaders. Resolvi então colocar estas pequenas coisas neste artigo.
Abaixo está o primeiro shader, ele recebe como parâmetro o nome de um arquivo de textura e o aplica a uma superfície.

Na linha 6, a variável Ct recebe a cor da textura. Isto é feito através da função texture que tem neste exemplo os parâmetros: o nome da textura (texturename), as coordenadas do ponto (s e t), o parametro extra “fill” e o seu valor 1.
A primeira observação é que a função texture pode retornar valores dos tipos float ou color, então temos sempre que utilizar um “cast” para definirmos que tipo de valor de retorno queremos. Se o tipo for color, por default, ela retorna os canais de índices 0,1 e 2 que correspondem à cor. Já se o “cast” for float, devemos especificar qual canal queremos. Normalmente utilizamos o float para lermos o alpha da imagem, o canal de índice 3.
O parâmetro extra “fill” é utilizado para ajustar um valor de retorno para situações em que a função texture não retorna um valor válido. Como por exemplo quando buscamos a informação de alpha de uma imagem que não contém alpha.
Existem diversos parâmetros extras e formas de chamar a função texture; para mais informações consulte a documentação do RenderMan.
Depois de compilarmos o shader e carregá-lo no Maya, para testá-lo precisamos de uma imagem. O RenderMan não manuseia arquivos de imagem comums (tiff, jpg, iff) mas um formato proprietário (normalmente estes arquivos são nomeados com o sufixo .tex). Então precisamos converter a imagem para este formato .tex utilizando o aplicativo txmake (ele é instalado automaticamente tanto no RAT como no RfM).
|
Para os próximos exemplos utilizaremos uma imagem chamada de textura1.tif que está gravada no diretório c:\temp.
Para convertê-la em .tex executamos o seguinte comando:
C:\temp> txmake textura1.tif textura1.tex
No Maya podemos incluir no atributo texturename a localização do arquivo de textura, veja na figura ao lado o attribute editor do primeiro shader. Repare que colocamos o caminho para o arquivo com barras invertidas como se fosse um sistema unix. Mesmo que exista espaços em branco no nome dos diretórios, não precisamos colocar o path entre aspas.
Nas figuras abaixo temos três renders diferentes. À esquerda o RenderMan Shader filemapping1.slo aplicado ao plano e processado pelo RfM. No meio, um surfaceShader/file texture do Maya aplicado ao plano e processado pelo RfM. Na esquerda, com um surfaceShader/file texture do Maya aplicado ao plano e processado pelo render do Maya. Modifiquei o background para cinza para melhor visualização.
A tradução feita pelo RfM dos shaders do Maya é correta e idêntica ao render do Maya; já a interpretação feita pelo RfM do nosso primeiro shader é diferente em dois pontos: a textura não foi esticada e esta invertida na vertical.
Na verdade, a maneira como o txmake traduz a imagem para um arquivo de textura é que vai determinar como será aplicada a textura na superfície. Para que tenhamos a conversão idêntica no RfM da maneira como o Maya trabalha, a sintaxe correta do txmake é:
C:\temp> txmake –mode periodic –resize up- arqEntrada arqSaida
O parâmetro –mode periodic ajusta a textura para fazer a sua repetição para cada valor de s e t fora da faixa de 0 a 1. Já o parâmetro -resize up- faz com que a textura seja escalada para que cubra a superfície inteira.
Aplicando isso ao exemplo, criamos um novo arquivo de textura:
C:\temp> txmake –mode periodic –resize up- textura1.tif textura2.tex
|
Ao lado está o render já com a textura2.tex aplicada ao plano. Ainda temos o problema da textura estar invertida em t. Isso ocorre porque a maneira como o RenderMan e o Maya interpretam a superfície para fazer a colocação da textura é diferente. Quando o RfM traduz um shader do Maya, ele faz a conversão, o mesmo já não acontece nos shaders escritos em RSL. Para termos o mesmo comportamento precisamos inverter o valor em t. Veja a sexta linha do shader filemapping2.sl no lugar de t, agora temos (1-t).
|
Após compilarmos, carregarmos no Maya e ajustarmos o atributo texturename para o arquivo textura2.tex, temos o resultado a imagem ao lado:
Se você pretende que os shaders possam ser utilizados tanto no RAT como no RfM, é necessário colocar uma variável que indique como t vai ser interpretado. No shader abaixo criamos o parâmetro isRfM, caso seu valor seja 1, temos t sendo interpretado de forma invertida (padrão RfM), para qualquer outro valor utilizamos t sem a inversão (padrão RAT).

Como mencionado anteriormente, podemos também acessar a máscara da imagem. É imprescindível se desejarmos aplicar texturas como decalques em superfícies. O próximo shader leva em consideração a máscara da textura para definir a opacidade da superfície.
|
Usando o shader filemapping4.slo temos a imagem à esquerda. Agora a parte visivel do plano é apenas aquela contida na máscara da imagem.
Na linhas 16 e 17 temos:
opacity= float texture(texturename[3],s,tt);
Ct= color texture(texturename,s,tt,"fill",1);
Na linha 16, a variável opacity recebe o valor da máscara. Reparem nas diferenças em relação a chamada da função texture na linha 17. Primeiro, o “cast” float e depois a referência ao canal [3] em texturename.
Repare que a maneira como escolhemos os canais se parece com a que utilizamos nos arrays. Isto acontece porque esta chamada aos canais de textura foi implementada quando a linguagem ainda não suportava arrays. Quando arrays foram adicionados criou-se uma pequena confusão. O compilador consegue distinguir muito bem o que queremos fazer a não ser quando temos um array de strings com nomes de arquivos e queremos utilizar este array na função texture. Temos então, que usar parenteses como separadores. Veja o exemplo abaixo:
string files[5];
Ci = float texture ((files[i])[3], s, t);
No próximo e último shader temos uma variação em relação ao anterior. Agora utilizamos o parâmetro surfacecolor para controlar a cor da superfície. A textura dada em texturename é aplicada como se fosse um decalque sobre a superficie, utilizando a máscara aplicamos somente a parte válida da imagem respeitando as transparências.
|
A imagem ao lado é o resultado do shader filemapping5.slo com o atributo surfacecolor ajustado para azul.
Estes exemplos são apenas uma introdução sobre o que se pode fazer na manipulação de texturas. Como exercício podemos pensar no que seria um próximo passo. Que tal criarmos um shader que sobreponha diversos layers de imagens, utilizando diversos esquemas de sobreposição (Add, Multiply, etc)? Ou ainda um esquema de posicionamento das texturas de uma forma analoga ao nodo place2Dtexture do Maya? Agora é só programar…
O Arquivo com os shaders e texturas usadas neste artigo:fileMappingFiles.zip