Mcronin Posted October 18, 2003 Share Posted October 18, 2003 OK, I'm trying to port Matt Pharr's skin shader for Entropy to VEX. I've gotten it to compile and it works, sorta... The shader is very dark (I have to jack up my color setting way over 1.0 to get something that looks even remotely like his shader) and I've got a dark halo. This is my first serious attempt at writing VEX, and I'm sure I'm doing something wrong. Would anyone mind taking a look at the code and telling me what's up. Also, the illuminance function. I can't find documentation on it. Can anyone point me to it? I tried specifying PI/2 and vcc complained about not knowing what PI is. It compiled when I tried nothing as below, and I also tried (3.14etc/2) and it made no difference. Does Illuminance default to PI/2 like the Illuminance VOP does? Matt's explanation can be found in the 2001 Renderman notes here: http://www.renderman.org/RMR/Books/sig01.c...course48.pdf.gz Matt's code /* Evaluate the Henyey-Greenstein phase function for two vectors with an asymmetry value g. v1 and v2 should be normalized and g should be in the range (-1, 1). Negative values of g correspond to more back-scattering and positive values correspond to more forward scattering. */ float phase(vector v1, v2; float g) { float costheta = -v1 . v2; return (1. - g*g) / pow(1. + g*g - 2.*g*costheta, 1.5); } /* Compute a the single-scattering approximation to scattering from a one-dimensional volumetric surface. Given incident and outgoing directions wi and wo, surface normal n, asymmetry value g (see above), scattering albedo (between 0 and 1 for physically-valid volumes), and the thickness of the volume, use the closed-form single-scattering equation to approximate overall scattering. */ float singleScatter(vector wi, wo; normal n; float g, albedo, thickness) { float win = abs(wi . n); float won = abs(wo . n); return albedo * phase(wo, wi, g) / (win + won) * (1. - exp(-(1/win + 1/won) * thickness)); } vector efresnel(vector II; normal NN; float eta; output float Kr, Kt;) { vector R, T; fresnel(II, NN, eta, Kr, Kt, R, T); Kr = smoothstep(0., .5, Kr); Kt = 1. - Kr; return normalize(T); } /* Implements overall skin subsurface shading model. Takes viewing and surface normal information, the base color of the skin, a color for an oily surface sheen, the ratio of the indices of refraction of the incoming ray (typically ~1 for air) to the index of refraction for the transmitted ray (say something like 1.4 for skin), and the overall thickness of the skin layer. Then loops over light sources with illuminance() and computes the reflected skin color. */ color subsurfaceSkin(vector Vf; normal Nn; color skinColor, sheenColor; float eta, thickness) { extern point P; float Kr, Kt, Kr2, Kt2; color C = 0; vector T = efresnel(-Vf, Nn, eta, Kr, Kt); illuminance(P, Nn, PI/2) { vector Ln = normalize(L); vector H = normalize(Ln + Vf); if (H . Nn > 0) C += Kr * sheenColor * Cl * (Ln . Nn) * pow(H . Nn, 4.); C += Kr * sheenColor * Cl * (Ln . Nn) * .2; vector T2 = efresnel(-Ln, Nn, eta, Kr2, Kt2); C += skinColor * Cl * (Ln . Nn) * Kt * Kt2 * (singleScatter(T, T2, Nn, .8, .8, thickness) + singleScatter(T, T2, Nn, .3, .5, thickness) + singleScatter(T, T2, Nn, 0., .4, thickness)); } return C; } /* Basic surface shader that uses the skin reflection model implemented above. Uses Cs for the basic color of the skin (.8, .5, .5) works reasonably well for Caucasian skin. */ surface skin(color Ka = .5; color sheenColor = 1.; float eta = 1./1.4, thickness = .5) { normal Nn = faceforward(normalize(N), I); vector Vf = -normalize(I); Oi = Os; Ci = Os * subsurfaceSkin(Vf, Nn, Cs, sheenColor, eta, thickness); } My Code //Lables for the SHOP #pragma opname v_LayeredSkin #pragma oplabel "VEX Layered Skin" #pragma opicon SHOP_surface //Labels for parameters #pragma label diffD "Dermis Color" #pragma label diffS "Sheen Color" #pragma label ior "IndexofRefraction" #pragma label thickness "Thickness" //Paramter types #pragma hint diffD color #pragma hint diffS color #pragma hint ior float #pragma hint thickness float /* Evaluate the Henyey-Greenstein phase function for two vectors with * an asymmetry value g. v1 and v2 should be normalized and g should * be in the range (-1, 1). Negative values of g correspond to more * back-scattering and positive values correspond to more forward scattering. */ float phase(vector v1, v2; float g;) { float costheta = -(dot(v1, v2)); return (1.0 - g*g) / pow(1.0 + g*g - 2.0*g*costheta, 1.5); } /* Compute a the single-scattering approximation to scattering from * a one-dimensional volumetric surface. Given incident and outgoing * directions wi and wo, surface normal n, asymmetry value g (see above), * scattering albedo (between 0 and 1 for physically-valid volumes), * and the thickness of the volume, use the closed-form single-scattering * equation to approximate overall scattering. */ float singleScatter(vector wi, wo, n; float g, albedo, thickness;) { float win = abs(dot(wi, n)); float won = abs(dot(wo, n)); return albedo * phase(wo, wi, g) / (win + won) * (1.0 - exp(-(1/win + 1/won) * thickness)); } vector efresnel(vector II, NN; float eta, Kr, Kt;) { vector R, T; fresnel(II, NN, eta, Kr, Kt, R, T); Kr = smooth(0.0, 0.5, Kr); Kt = 1.0 - Kr; return normalize(T); } /* Implements overall skin subsurface shading model. Takes viewing and surface normal information, the base color of the skin, a color for an oily surface sheen, the ratio of the indices of refraction of the incoming ray (typically ~1 for air) to the index of refraction for the transmitted ray (say something like 1.4 for skin), and the overall thickness of the skin layer. Then loops over light sources with illuminance() and computes the reflected skin color. */ vector subsurfaceSkin(vector Vf, Nn, skinColor, sheenColor; float eta, thickness;) { float Kr, Kt, Kr2, Kt2; vector C = 0; vector T = efresnel(-Vf, Nn, eta, Kr, Kt); illuminance(P, Nn) { vector Ln = normalize(L); vector H = normalize(Ln + Vf); if (dot(H, Nn) > 0) C += Kr * sheenColor * Cl * (dot(Ln, Nn)) * pow(dot(H, Nn), 4.0); C += Kr * sheenColor * Cl * (dot(Ln, Nn)) * 0.2; vector T2 = efresnel(-Ln, Nn, eta, Kr2, Kt2); C += skinColor * Cl * (dot(Ln, Nn)) * Kt * Kt2 * (singleScatter(T, T2, Nn, 0.8, 0.8, thickness) + singleScatter(T, T2, Nn, 0.3, 0.5, thickness) + singleScatter(T, T2, Nn, 0.0, 0.4, thickness)); } return C; } /* Basic surface shader that uses the skin reflection model implemented above. Uses Cs for the basic color of the skin (.8, .5, .5) works reasonably well for Caucasian skin. */ surface skin(vector diffD=.5; vector diffS=1; float ior=1; float thickness=.5;) { vector Nn = frontface(normalize(N), I); vector Vf = -(normalize(I)); float eta = (ior/1.4); Cf = subsurfaceSkin(Vf, Nn, diffD, diffS, eta, thickness); } Also, note that I'm a barely competent C/C++ programmer and this is my first stab at writing a shader in VEX. Please tell me if I've done anything stupid from a coding standpoint, aside from whatever I did wrong that's causing the problems I stated above. EDIT: don't mention the formatting When I copied and pasted the code my formatting got blown away Quote Link to comment Share on other sites More sharing options...
edward Posted October 18, 2003 Share Posted October 18, 2003 I haven't looked at your code but here's some tips for using vex: - Look in the main help contents "VEX Reference" web page. You can also use a regular page with help function if you're on Linux using the URL at the top if you want. - Look in $HH/vex/include. I believe you need to include math.h in order to have PI or M_PI depending on your vcc options. prman.h is also instructive for converting prman to vex shaders. - For VOP to VEX comparisons, it's very easy to right-click on the output node and choose "View Code...". Quote Link to comment Share on other sites More sharing options...
Mcronin Posted October 20, 2003 Author Share Posted October 20, 2003 Thanks for the info, Edward. I'm getting to the problem now. It has to do with Matt's efresnel function, specficly how he handles Kt. He presents a fix for fresnel fuctions that mishandle Kt and it's different than what's recommended in the VEX docs. Anyway, I've figured a kludge now that generates something that looks like his shader... unfortuanely it just not a really good skin solution Time to try something else. I was looking at the Renderman notes from last Siggraph, and both Pixar and ILM presented solutions that require referencing the irradiance cache. Can this be done in VEX? I found the irradiance function in VEX, but no way to reference an external cache. Quote Link to comment Share on other sites More sharing options...
mike Posted October 20, 2003 Share Posted October 20, 2003 hi, i have done the same combined with a colortexture. works fine. ( i have changed some params sligthly ). // rewritten and combined with texturing #pragma hint texlightness color #pragma hint uv hidden #pragma hint texmap file #include <prman.h> #include <shading.h> #include <vexnotes.h> #include <math.h> float phase(vector v1, v2; float g) { float costheta = dot(-v1,v2); return (1. - g*g) / pow(1. + g*g - 2.*g*costheta, 1.5); } float singleScatter(vector wi, wo; normal n; float g, albedo, thickness) { float win = abs(dot(wi,n)); float won = abs(dot(wo,n)); return albedo * phase(wo, wi, g) / (win + won) * (1. - exp(-(1/win + 1/won) * thickness)); } vector efresnel(vector II; normal NN; float eta;output float Kr, Kt;) { vector R, T; fresnel(II, NN, eta, Kr, Kt, R, T); Kr = smoothstep(0., .4, Kr); Kt = 1. - Kr; return normalize(T); } vector subsurfaceSkin(vector Vf, Nn, texlightness, sheenColor; float eta, thickness) { vector P; float Kr, Kt, Kr2, Kt2; vector C = {0,0,0}; vector T = efresnel(-Vf, Nn, eta, Kr, Kt); vector T2; illuminance(P, Nn, PI /2 ) { vector Ln = normalize(L); vector H = normalize(Ln + Vf); if (dot(H,Nn) > 0) C += Kr * sheenColor * Cl * dot(Ln,Nn) * pow(dot(H,Nn), 2.); //4. C += Kr * sheenColor * Cl * dot(Ln,Nn) * .3; T2 = efresnel(-Ln, Nn, eta, Kr2, Kt2); C += texlightness * Cl * dot(Ln,Nn) * Kt * Kt2 * (singleScatter(T, T2, Nn, .8, .8, .5) + singleScatter(T, T2, Nn, .3, .5, .5) + singleScatter(T, T2, Nn, 0., .4, .5)); } return C; } // Basic surface shader that uses the skin reflection model implemented // above. surface skin_tex( float Kd = 1.1 ; vector texlightness = 1; float eta = .28; string texmap =""; vector uv = 0; ) { vector rest = 0; vector sheenColor; float thickness = .5; float ss, tt; vector Nn,Vf; if (isbound("uv")) { ss = uv.x; tt = uv.y; } else { ss = s; tt = t; } Nn = faceforward(normalize(N), I); Vf = -normalize(I); Oi = Os; sheenColor =(vector(texture(texmap, ss, tt)))*Kd; Ci *= subsurfaceSkin(Vf, Nn, texlightness,sheenColor, eta, thickness); 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.