Jump to content

new PBR shader features in H12.5


danylyon

Recommended Posts

Hi guys

I stumbled upon cvex_bsdf() vex function, that's new in H12.5 and really awesome!

It basically let's you do your own Specular or Diffuse lobe... a BSDF function. (Same as the build in primitiv BSDF like the phong, phonglobe, ashkhim etc.)

You can read about it in the Help Docs: http://www.sidefx.co...tions/cvex_bsdf

Unfortunatly it's quite challenging (or at least for me).. because it's not just an illuminance loop that needs to be coded. But also a PDF and a sampling function.

Basically two shaders need to be written. One more or less a common "illuminance" loop.. and one that will shoot samples (in directions that are relevant!) and needs to tell how probable that sample direction is (the PDF, read more here: http://en.wikipedia....ensity_function )

That's quite some Math :-)

What I still don't quite understand (maybe somebody has a clearer undestanding).. what the "refl" is good for. As far as I undestand, it's the total reflectivity of the shader, based on roughness.. so it can be normalized / energy conserved.

I tried to do my own implementation of ashikhim.

It seems to work ok.. it looks slightly different than the build in.. still have to figure that out.

It doesn't split anything correctly into aov's yet (the standart PBR's)

The implementation of MIS in mantra is a bit special, as it doesn't seem to allow Fresnel on the BSDF level... still have to look into that more..

Heres the code (without the Fresnel term!!, hat needs to be added in the actual shader. That calls these CVEX functions.):

specular_eval.vfl:


#include "pbr.h"
#pragma range ex_nu 0 1000
#pragma range ex_nv 0 1000
#define PI 3.14159265358979323846
#define TWO_PI 6.283185307179586

// given incident Light, calculates the reflectivity at view vector
vector ReflAS(vector L, Nn, V; vector tanu, tanv; float nu, nv;)
{
float NdotV = dot(Nn,V);
vector H = normalize(L+V);
float NdotL = dot(Nn,L);
float HdotV = dot(H,V);
float HdotX = dot(H,tanu);
float HdotY = dot(H,tanv);
float NdotH = dot(Nn,H);
float norm_s, n;
if (nv == nu) // isotropic ?
{
norm_s = (nu + 1) / (8*PI);
n = nu;
}
else
{
norm_s = sqrt((nu + 1) * (nv + 1)) / (8*PI);
n = (nu * HdotX * HdotX + nv * HdotY * HdotY) / (1 - NdotH * NdotH);
}

float rawR = norm_s * 1 * pow( max(NdotH, 0), n) / (HdotV * max(NdotV, NdotL));
return rawR;
}

cvex specular_eval(
vector u = 0; // Outgoing light direction, from the surface to the viewer
vector v = 0; // Incoming light direction, from the surface to the light
int bounces = 0;
export vector refl = 1;
export vector eval = 1; // Delta bsdf
vector Nn = 0;
float ex_nu = 100, ex_nv = 100;
vector tanU = {0,0,0}, tanV = {0,0,0} // tangent vectors
{
eval = ReflAS(v, Nn, u, tanU, tanV, ex_nu, ex_nv); // reacts only to lights in scene!?
refl = 1; // specular is energy conserving

}
[/CODE]

specular_sample.vfl

[CODE]
#include "pbr.h"
#define PI 3.14159265358979323846
#define HALF_PI 1.57079632679489655800
#define TWO_PI 6.283185307179586

float calcPhi(float nu,nv,rnd;)
{
return atan(sqrt( (nu + 1) / (nv + 1) ) * tan(HALF_PI * rnd));
}

// generates a Sample (S) assuming light coming from direction L, and assigns a probability to pdf
void SampleAS(vector L, Nn; float sx, sy; float nu, nv; vector tanu, tanv; export float pdf; export vector S;)
{
int iso = (nu == nv); // isometric?
float phi = 0; // random angle around the pole
if(iso) phi = sx * TWO_PI;
else
{
if (sx < 0.25) phi = calcPhi(nu, nv, 1 - 4*(0.25 - sx));
else if (sx >= 0.25 && sx < 0.5) phi = calcPhi(nu, nv, 1 - 4*(0.5 - sx)) + HALF_PI;
else if (sx >= 0.5 && sx < 0.75) phi = calcPhi(nu, nv, 1 - 4*(0.75 - sx)) + PI;
else phi = calcPhi(nu, nv, 1 - 4*(1 - sx)) - HALF_PI;
}
float cosph = cos(phi);
float sinph = sin(phi);
float theta = 0;
if (iso) theta = acos( pow (1 - sy, 1 / (nu + 1)));
else theta = acos( pow (1 - sy, 1 / (nu * cosph * cosph + nv * sinph * sinph + 1))); // random angle between sample and pole
vector xir = tanu;
vector yir = tanv;
if (iso)
{
yir = normalize(cross(Nn,L));
xir = normalize(cross(Nn,yir));
}
vector Sh = cosph * sin(theta) * xir + sinph * sin(theta) * yir + cos(theta) * Nn;
float LdotH = dot(L,Sh);
S = -L + 2 * LdotH * Sh; // calculating sample vector
float NdotV = dot(Nn,S);
if (NdotV < 0) // below horizon?
{
S = reflect(S,-Nn);
NdotV = dot(Nn,S);
}
float HdotX = dot(Sh,tanu);
float HdotY = dot(Sh,tanv);
float NdotH = dot(Nn,Sh);
float HdotV = dot(Sh,S);
float PDFh;
if (iso) PDFh = (nu + 1) / TWO_PI * pow(NdotH, nu * (HdotX * HdotX + HdotY * HdotY));
else PDFh = sqrt((nu + 1)*(nv + 1)) / TWO_PI * pow(NdotH, nu * HdotX * HdotX + nv * HdotY * HdotY);
pdf = PDFh / (4 * LdotH) * TWO_PI; // probability for Sample, normalized over sphere * TWO_PI
}

cvex specular_sample(
vector u = 0; // surface to viewer vector
float sx = 0; // random numbers given by Mantra
float sy = 0;
int bounces = 0;
export vector refl = 0;
export vector v = 0; // light direction to be sampled, from the surface to the light
export int bouncetype = 0;
export float pdf = 0; // The sampling pdf.
// The uniform integration of this value over the sphere should be a constant 2*PI!
vector Nn = 0;
float ex_nu = 100, ex_nv = 100; // spec exponent
vector tanU = {0,0,0}, tanV = {0,0,0};) // tangent vectors
{
if (bounces & PBR_REFLECT_MASK)
{
SampleAS(u, Nn, sx, sy, ex_nu, ex_nv, tanU, tanV, pdf, v);
refl = 1;
bouncetype = PBR_REFLECT_MASK;
}
}
[/CODE]

Disclaimer: This is not production ready!.. it's not a complete shader. I'm just sharing to see if some people have some inputs. And maybe it's of some help to someone..

BUG? The revlectivity of a lightsource is different to the build in one (will look into that).

If you want to intall and test.

Put them both into separate files (specular_eval.vfl and specular_sample.vfl respectivly)

compile both (vcc specular_eval.vfl / vcc specular_sample.vfl)

put the vex files into \Houdini 12.5.316.22\houdini\vex\CVex

Make a new shader in Houdini and call them like this:

specBSDF = cvex_bsdf("specular_eval", "specular_sample", "label", "reflect", "Nn", Nn, "ex_nu", nu, "ex_nv", nv, "tanU", tanU, "tanV", tanV);

F = specBSDF;

Any comments would greatly help..

Edited by danylyon
  • Like 1
Link to comment
Share on other sites

I found the problem with the reflectivity of the lightsource (area).

It seems the eval in specular_eval needs to be multiplied by 2 PI. No idea why, Also, it seems the Specular functions don't include the NdotL term. That gets probably mutliplied in the renderer directly (so it can be removed in my code aswell)..

Oddly.. if I set the pdf to zero, nothing changes (same time, same samplecount). I'm not sure if it actually needs it.

(So you can't "delete" rays if you set their PDF to zero, that's why I reflect the rays below the horizon)

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Hey Dany,

When writing a general vex shader for PBR, do we have access to L ? For some reason just doing a simple test with a point light, there are no errors when I reference L but any computation with it doesn't seem to produce expected results. would we need an illuminance loop for this?

Link to comment
Share on other sites

  • 11 months later...

I've just started trying to implement a BSDF myself (using GGX as an exercise) and noticed exactly what you did... that it seems the eval function must be multiplied by 2*PI, and there is no need for f * cos(N,L) (edit:  maybe NdotL is needed... seems necessary to eliminate hard edges with wide speculars).  Did you ever find out why?

 

Also, when I compare a white environment light using MIS -1, 1... the edges darken with MIS of 1, but not with -1... this is probably a mistake in my code somewhere, but if you think there is something obvious I'm missing I would love to hear it.

 

-Jon

 

I found the problem with the reflectivity of the lightsource (area).
It seems the eval in specular_eval needs to be multiplied by 2 PI. No idea why, Also, it seems the Specular functions don't include the NdotL term. That gets probably mutliplied in the renderer directly (so it can be removed in my code aswell)..

Oddly.. if I set the pdf to zero, nothing changes (same time, same samplecount). I'm not sure if it actually needs it.
(So you can't "delete" rays if you set their PDF to zero, that's why I reflect the rays below the horizon)

Edited by jonp
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...