Wednesday, April 01, 2015

REYES

So porque agora tem RIS no renderman não quer dizer que o REYES  nao serve mais pra nada : )

testezinho que fiz com  GeoAreaLight , GI/colorbleeding    , Displacement e GPSurface


Renderman For Maya 5.5 RMS 19.0 MARI e PxrTexture Node

Depois de a Pixar liberar uma copia gratis para todo mundo ter em casa o Renderman . resolvi voltar a mexer nele .  Bem feliz com essa versao .. PBR e GXX shaders   sao bem legais .. depois de um bom tempo usando VRAY   voltar no renderman com pathtracing eh uma experiencia legal ..
como teste  resolvi unir duas coisas que eu tinha vontade de experimentar numa pipeline . o MARI e o Renderman  ..
UDIM uvs   nunca usei diretamente . porque sempre achei terrivel o modo de conectar o nodes no maya , muito trabalho para ajustar a cada nova mudança de path , e super facil de ocorrer erros ...
mas o renderman tem um node legal de textura que facilita muito o trabalho de ajuste  ..
o PxrTexture   ,   nele voce pode puxar o preset do MARI atlas  que existia no SLIM dentro do maya .. eh bem facil de usar .  seleciona o MARI na lista de Atlas style . e adiciona o primeiro arquivo da sequencia no filename ..  C:/CHRYSL666/ladybug/MARI/colorflattened.1001.tx ..  existe uma pegadinha , para o RM saber como mapear o mapa certo no objeto e UV DIM correto eh preciso editar o nome do path  . e trocar o numero do mapa para "_MAPID_"  no final o path fica assim
...C:/CHRYSL666/ladybug/MARI/colorflattened._MAPID_.tx...
isso eh o suficiente para o RM saber o que fazer ..  entao resumindo, com um shader e somente um node de textura . voce mapea todos os UDIM de uma vez so . sem precisar daquelas conexões gigantes que c faziam antes no maya .


Não sei c voces notaram mas o formato de arquivo que estou usando eh o pixar .tx ..  o renderman em geral converte todos os arquivos que vc passa pra ele para esse formato . o MARI não gera esse tipo de arquivo . no MARI eu exporto .exr  , mas como andei tendo uns problemas de conversão interna no renderman . eu converto os mapas manualmente . eh possivel usar o renderGlobals para criar um processo de coversão automatica dos mapas . mas eu por costume . uso o txmake . que eh um programa de coversão que vem no prman .  ele fica na pasta /bin da instalação do programa .. a linha de comando eh simples   txmake [nomedoarquivoOrginal.exr]  [nomedoarquivoFinal.tx]   isso faz com que ele converta os arquivos pro formato certo .. existem muitas opçoes diferentes de uso  desse programa .. olhem o txmake -h para ver os exemplos ..   o txmake faz um arquivo por vez . nao sei c existe uma linha de comando para multiplos arquivos .. mas eh possivel automatizar as coisas com scripts  ..  aqui no meu minipipe  fiz um programinha em c++ Qt  para acelerar minhas conversões de uma pasta especifica . c alguem precisar de um exemplo  segue aqui  o source code do meu ...


1:  #include <QCoreApplication>  

2:  #include <QDebug>
3:  #include <QDir>
4:  #include <QFileInfo>
5:  #include <QString>
6:  #include <QProcess>
7:  int main(int argc, char *argv[])
8:  {
9:    QCoreApplication a(argc, argv);
10:    // path para o txmake
11:    QString program = "C:\\Temp\\txmake";
12:    // cria objeto para executar o txmake
13:    QProcess myProcess ;
14:    // captura a pasta dentro do mDir
15:    QDir mDir("C:/CHRYSL666/ladybug/MARI");
16:    // para cada item dentro da pasta
17:    foreach(QFileInfo mitm , mDir.entryInfoList())
18:    {
19:      // c o item for um arquivo
20:      if(mitm.isFile())
21:      {
22:        // verifica c eh um arquivo de exr
23:        QString ext = mitm.suffix(); // ext = "exr"
24:        if(ext == "exr")
25:        {
26:          // c for um arquivo de exr pega o path e o nome do arquivo
27:          QString exrFileName = mitm.absoluteFilePath();
28:          // separa o path do nome
29:          QString mainPath = mitm.absolutePath();
30:          // captura o nome do artrquivo sem a extensão
31:          QString fileName = mitm.completeBaseName();
32:          // cria o novo path e nome do arquivo com a extensao tx da pixar
33:          QString newName = mainPath+"/"+fileName+".tx";
34:          // cria uma lista de argumentos para usar com o txmake
35:          QStringList arguments;
36:          arguments << exrFileName << newName ;
37:          qDebug() << " converting EXR images to pixar TX" ;
38:          int status = myProcess.execute(program , arguments);
39:          if(status != 0 )
40:          {
41:            qDebug() << "file:" << newName << "Error : " << status ;
42:          }
43:          else
44:          {
45:            qDebug() << "file:" << newName << "Created : " << status ;
46:          }
47:        }
48:      }
49:    }
50:    return a.exec();
51:  }

Sunday, December 25, 2011

Spherical Harmonics

  • Spherical Harmonics com e sem Occ







Spherical Harmonics eh uma tecnica usada muito em games para criar falsa iluminacao ambiente nos objetos , ele dispensa o uso de HDRI para simular a irradiancia sobre o difuse de um shader , apesar da matematica envolvida ser cheio de letras e numeros malucos a aplicacao eh bem simples usando um pouco a ajuda e o programa do paper :

esse paper explica que voce pode pegar todos os valores de "luma"!!! :P atraves de 9 coeficientes processados de um mapa de HDR .. esses coeficientes sao depois multiplicados sobre o diffuse
a formula eh isso aqui :

vector DiffuseColor = vector ( C1 * L22 * (tnorm[0] * tnorm[0] - tnorm[1] * tnorm[1]) +C3 * L20 * tnorm[2] * tnorm[2] +C4 * L00 -C5 * L20 +2.0 * C1 * L2m2 * tnorm[0] * tnorm[1] +2.0 * C1 * L21 * tnorm[0] * tnorm[2]+2.0 * C1 * L2m1 * tnorm[1] * tnorm[2] +2.0 * C2 * L11 * tnorm[0] +2.0 * C2 * L1m1 * tnorm[1] + 2.0 * C2 * L10 * tnorm[2] );

onde cada c1 c2 c3 etc .. sao numeros constantes indicados no paper .. e o L22 L11 etc .. sao coeficientes processados do HDRI ... existe uma tabela de mapas HDRI mais conhecidos para ser usados de exemplo .. o que eu usei eh o mapa Grace cathedral , c for preciso novos coficientes de mapas propios . o paper fornece um codigo em "C" que extrai os coeficientes para voce de um novo mapa , nao testei ainda . mas acho que eh possivel transformar esse codigo em um DSO para o renderman . assim extrair o coeficiente em renderTime c for o caso ... aqui vai a tabela :

um detalhe, como essa eh uma tecnica para produzir luz ambiente . ela nao gera sombra, alguns papers na net demonstram outras formas de usar esse calculo para retirar
o sample de cor pra producao de bleeding e sombras usando raytracing . mas basicamente
eh um looping de gather conferindo onde o raio obteve ou nao colisao , caso nao , ele utiliza o spherical harmonic para produzir o occlsuion , aqui . eu usei um simples occlusion do renderman para produzir isso. detalhe spherical harmonics pode ser usados tbm na composicao .. caso voce tenha um pass de normal ... no video "Nuke master Class de Roy Stelzer" encontrado no propio site da Foundry .. ele demonstra como aplicar isso ..

bem segue o codigo do shader :


  • surface spherical(float scalefactor = .2 , samples = 32 , occOnOff = 0.0)
  • {
  • // spherical harmonics coeficients
  • float C1 = 0.429043;
  • float C2 = 0.511664;
  • float C3 = 0.743125;
  • float C4 = 0.886227;
  • float C5 = 0.247708;
  • // Constants for Old Town Square lighting
  • vector L00 = vector( .79, .44, 0.54);
  • vector L1m1 = vector( 0.39, 0.35, 0.60);
  • vector L10 = vector( -0.34, -0.18, -0.27);
  • vector L11 = vector(-0.29, -0.06, .01);
  • vector L2m2 = vector(-0.11, -0.05, -0.12);
  • vector L2m1 = vector( -0.26, -0.22, -0.47);
  • vector L20 = vector(-0.16, -0.09, -0.15);
  • vector L21 = vector(0.56, 0.21, .14);
  • vector L22 = vector(.21, -0.05, -0.30);
  • vector tnorm = vector(faceforward(normalize(N),I));
  • vector DiffuseColor = vector ( C1 * L22 * (tnorm[0] * tnorm[0] - tnorm[1] * tnorm[1]) +
  • C3 * L20 * tnorm[2] * tnorm[2] +C4 * L00 -
  • C5 * L20 +
  • 2.0 * C1 * L2m2 * tnorm[0] * tnorm[1] +
  • 2.0 * C1 * L21 * tnorm[0] * tnorm[2]+
  • 2.0 * C1 * L2m1 * tnorm[1] * tnorm[2] +
  • 2.0 * C2 * L11 * tnorm[0] +
  • 2.0 * C2 * L1m1 * tnorm[1] +
  • 2.0 * C2 * L10 * tnorm[2] );
  • //occlusion
  • float average;
  • normal n = normalize(N),
  • nf = faceforward(n, I);
  • float hits = 0;
  • if(occOnOff != 0.0)
  • {
  • gather("illuminance", P, nf, PI/2, samples, "distribution","cosine")
  • {
  • hits += 1;
  • }
  • average = hits / samples;
  • }
  • else
  • {
  • average = 0;
  • }
  • Ci = (color(DiffuseColor * scalefactor)) - average;
  • Oi = 1;
  • }



  • Monday, October 31, 2011

    subSurface

    Fiz um teste de shader de SSS no 3delight .. modelo e texturas nao sao meus ("http://www.ir-ltd.net/infinite-3d-head-scan-released) somente fiz a combinação de dois shader no maya cook torrance com SSS tanto no specular quanto no difusse ! e detalhes com displace ao invez de normal map .. o resultado ficou bem legal . levando em conta o pouco que precisei mexer nos shader pro resultado final ! mas tenho que admitir que o modelo e as texturas sao tao bons que mesmo um maya software tira um render bem aceitavel com esse modelo "D ..

    Tuesday, August 30, 2011

    Procedural Primitives 2


    Depois de brigar um pouco com o c++ consegui "traduzir" mais um exemplo de procedural
    primitives que vi em python para a linguagem c++ , dessa vez usando um exemplo de como gerar esferas dispostas aleatoriamente ao redor de uma esfera maior .
    o codigo praticamente o mesmo
    do exemplo anterior . com a diferenca
    da adicao de funcoes para sortear posicoes aleatorias e normalizacao dessas posicoes para chegar no formato da esfera maior , segue abaixo o codigo

    header:

    /*

    * RibBox.h

    * classExerc

    *

    * Created by chrysl666 on 8/27/11.

    * Copyright 2011 none. All rights reserved.

    *

    */


    #ifndef RIBBOX_H

    #define RIBBOX_H


    #include

    #include


    int const VECTOR_SIZE = 3;



    class RibBox

    {

    public:

    //constructor

    RibBox();

    //variaveis

    std::string parFromMaya ;// sent by renderman

    std::string details ;// got from splited[0]

    std::string number ;// got from splited[1]

    std::string width ;// got from splited[2]

    std::string radius ;// got from splited[3]

    double point[VECTOR_SIZE];// ponto aleatorio

    double normPoint[VECTOR_SIZE];// ponto apos normalizado

    double scalePnt[VECTOR_SIZE];// ponto apos scalado

    //funcoes

    void setRibBox(); // insert commands at render stream

    void getRibBoxPar(); // get par from renderman

    void Tokenize(const std::string& ,

    std::vectorstring>& ,

    const std::string& ); //tokenize

    void randomPoint(double rangeMin, double rangeMax );

    std::string formatTuple(std::string theTuple);

    void scalePoint();

    void normalize();

    double randWidth(std::string max);

    };


    #endif


    cpp:


    /*

    * RibBox.cpp

    * classExerc

    *

    * Created by chrysl666 on 8/27/11.

    * Copyright 2011 none. All rights reserved.

    *

    */


    #include

    #include

    #include

    #include

    #include


    #include "RibBox.h"




    RibBox::RibBox()

    {

    // construtor da classe

    //incializa o array point

    for(int i=0;i<3;i++)

    {

    point[i]=0;

    }


    }



    void RibBox::Tokenize(const std::string& str,

    std::vectorstring>& tokens,

    const std::string& delimiters = " ")

    {

    // tokenize function para separar as informacoes em strings

    // pula o delimitadores no inicio

    std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);

    // acha o primeiro nao delimitador

    std::string::size_type pos = str.find_first_of(delimiters, lastPos);

    while (std::string::npos != pos || std::string::npos != lastPos)

    {

    // achou um token , add no vetor.

    tokens.push_back(str.substr(lastPos, pos - lastPos));

    // pula delimitadores. Note o "nao_de"

    lastPos = str.find_first_not_of(delimiters, pos);

    // procura proximo "nao-delimitador"

    pos = str.find_first_of(delimiters, lastPos);

    }

    }




    void RibBox::getRibBoxPar()

    {

    //parsing comandos vindos dos renderman

    std::vectorstring> tokens; // um vector de string temporario

    std::getline(std::cin,parFromMaya);

    Tokenize(parFromMaya ,tokens);

    details = tokens[0];

    number = tokens[1];

    width = tokens[2];

    radius = tokens[3];

    }



    void RibBox::setRibBox()

    {

    //formatacao dos comandos de saida para o stream

    std::cout<<"AttributeBegin\n";

    std::cout<<"Points \"P\" [";

    for (int i=0; i< (atoi(number.c_str())); i++)

    {

    randomPoint(-1, 1);

    normalize();

    scalePoint();

    std::cout<0]<<" "<1]<<" "<2]<<" ";

    }

    std::cout<<"]\n";

    std::cout<<"\"width\" [";

    for (int i=0; i< (atoi(number.c_str())); i++)

    {

    std::cout<<randWidth(width)<<" ";

    }

    std::cout<<"] \n";

    std::cout<<"\"Cs\" [";

    for (int i=0; i< (atoi(number.c_str())); i++)

    {

    std::cout<<randWidth("1")<<" "<<randWidth("1")<<" "<<randWidth("1")<<" " ;

    }

    std::cout<<"]\n";

    std::cout<<"AttributeEnd\n";

    std::cout<<"\377"<

    }



    void RibBox::randomPoint(double rangeMin, double rangeMax )

    {

    //cria um valor aleatorio entre rangeMin e rangeMax para o arrayPoint

    double step = rangeMax - rangeMin ;

    for (int i=0; i<VECTOR_SIZE; i++)

    {

    point[i] = (step * static_cast <double> (rand ()) / static_cast <double> (RAND_MAX) -1);

    }

    }



    void RibBox::normalize()

    {

    double mag = sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]);

    for (int i=0; i<VECTOR_SIZE; i++)

    {

    normPoint[i] = point[i]/mag;

    }

    }



    void RibBox::scalePoint()

    {


    int radiusInt = atoi(radius.c_str());

    for (int i=0; i<VECTOR_SIZE; i++)

    {

    scalePnt[i] = normPoint[i] * radiusInt;

    }

    }



    double RibBox::randWidth(std::string max)

    {

    double maxInt = atof(max.c_str());

    return (maxInt * static_cast <double> (rand ()) / static_cast <double> (RAND_MAX));

    }

    e o main.cpp :


    #include

    #include

    #include

    #include

    #include "RibBox.h"



    int main (int argc, char * const argv[])

    {

    RibBox ribBoxObj;



    while(1)

    {

    ribBoxObj.getRibBoxPar();

    ribBoxObj.setRibBox();

    }


    }

    e o comando de insercao no maya :

    RiProcedural -pn "/Users/chrysl666/Desktop/devBook/classExerc02/build/Debug/classExerc02" -p "1000000 0.05 10" -b -1e38 1e38 -1e38 1e38 -1e38 1e38;