danylyon Posted March 26, 2013 Share Posted March 26, 2013 (edited) 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 vectorvector 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.283185307179586float 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 pdfvoid 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 poleif(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 polevector 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 vectorfloat 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\CVexMake 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 March 26, 2013 by danylyon 1 Quote Link to comment Share on other sites More sharing options...
danylyon Posted March 26, 2013 Author Share Posted March 26, 2013 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) 1 Quote Link to comment Share on other sites More sharing options...
Jason Posted March 26, 2013 Share Posted March 26, 2013 Yeah, this is really exciting new feature -- I am looking forward to digging into it a bit once we're in the clear here at work (provided that actually ever happens). Quote Link to comment Share on other sites More sharing options...
stevegh Posted May 20, 2013 Share Posted May 20, 2013 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? Quote Link to comment Share on other sites More sharing options...
stevegh Posted May 20, 2013 Share Posted May 20, 2013 (edited) Confirmed adding illuminance() worked nevermind! Edit: Please disregard that there wasn't a need to call it at all wooo Monday! Edited May 20, 2013 by stevegh Quote Link to comment Share on other sites More sharing options...
jonp Posted May 4, 2014 Share Posted May 4, 2014 (edited) 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 May 4, 2014 by jonp Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.