zbrush cavity shader in houdini?

   52796   35   1
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Hi!
Just out of curiosity and actually hoping the answer would be yes…
Within Houdini,would it be possible to recreate a cavity shader like the one found in Zbrush shaders? Without using ambient occlusion obvious and slower solution., and actually getting it almost “real-time”(just fast) like in Zbrush?

Here's a link to an exemple pic:
http://www.pixolator.com/zbc/attachment.php?attachmentid=54137 [pixolator.com]


This shader effect actually goes throught all crack and darkens the inside, this is really handy stuff!

So anybody knows this? thanks alot!!
JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
7710 posts
Joined: July 2005
Online
Well, if you have a displacement shader, then you can just export your displacement value to the surface shader. Then the surface shader can darken those areas.
User Avatar
Member
32 posts
Joined: July 2005
Offline
Check out this link:

http://www.zbrushcentral.com/zbc/showthread.php?t=25753 [zbrushcentral.com]

It details on methods of getting a map of the cavity shader's results out of Zbrush that may give you what you need a low tech fashion. Hope it helps.
-nimajneb
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Thanks guys.
I'm actually aware of how to import the cavity map from zbrush to houdini(or any other packages). I'm actually wondering if it's possible to emulate the actual cavity shader using vops within houdini, without cheating ?
JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
941 posts
Joined: July 2005
Offline
… real quick sketch (untested!):

#pragma hint uv hidden
shader cavity (
string bumpmap = “”; // cavity map (floating-point, preferably)
float bfloor = 0; // pixel value for “no bump”
int keepbelow = 1; // whether to use values below/above floor
float strength = 1; // Darkening strength
vector uv = 0; // texture uv's (hidden)
)
{
float Kcavity = 1; // cavity value
if(bumpmap!=“” && strength!=0) {
vector tuv = isbound(“uv”) ? uv : set(s,t,0);
vector mapval = texture(bumpmap,tuv.x,tuv.y,“filter”,“catrom”);
float depth = luminance(mapval)-bfloor;

depth = keepbelow ? max(0,abs(depth)) : max(0,depth);
Kcavity = exp(-5.0*strength*depth);
}
// Do usual shading…
Cf = diffuse()*Kcavity; // +…
F = bsdf(diffuse()) * Kcavity; // + …
}
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Hi mario thanks for the post!
I never did coded shaders with houdini yet…just used vops. But I can understand the big picture here! However(correct me if I'm wrong), but it's seems like your shader would need a bumpmap plugged into it? In Zbrush it work with the mesh itself, wherever there are “cracks”…

It's really an awesome shader, I wish other 3d apps could have that as fast as in Zbrush, but never ever saw it elsewehere.
JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
12433 posts
Joined: July 2005
Offline
For a purely geometry solution:

It reminds me of the “autovc” SOP on the Exchange. It smoothes the mesh and uses the difference in the point positions to colour the geometry.

Otherwise, to compute this at rendering time, it kinda looks like a touch of Ambient Occlusion with a very short maxdist, perhaps? Or maybe some concave features might be able to be detected using point-clouds too - although this would take a little development to get right.
Jason Iversen, Technology Supervisor & FX Pipeline/R+D Lead @ Weta FX
also, http://www.odforce.net [www.odforce.net]
User Avatar
Member
941 posts
Joined: July 2005
Offline
Yeah… at the geometry level, what Jason said. But since you mentioned “shader” and “cavity map” I figured you had some map with the cavity amplitudes. No matter what you do, if you want an actual shader (as opposed to some SOP-side point coloring OP), you'll have to pass the cavity information down to the shader somehow, and your only choices are maps or point attributes (and point attributes require a very hi-res mesh). The only other “quick” alternative on the shader side would be a curvature-based shader, but this works on all curvatures, not just the cavities (unless you masked it with another map) – and you'd have the same issue with a small-radius-occlusion approach.

So… since I haven't seen this “cavity map” that you mentioned… what is it exactly? It's not a texture map then?
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Hi guys, thanks gain for the answer.
Well, I guess Zbrush does it at the geometry level, but it as so many polygones that it doesn't show. I did a test for myself in Zbrush and joined a picture to my post.

It actually seem like cavity shader actual darkens every concave angles…and that's about it! From, what I can see, it doesn't seem to take anything else in account, what do you think? It doesn't seem to bother with the actual size of the cavity.

Now Mario, sorry for the confusion. When I talk about cavity maps, is that you can actually extract a “cavity map” from zbrush, so zbrush renders out an unfolded cavity texture to use outside zbrush, but it can be heavy you know. I would prefer to be able to generate the effect directly on my shader(or geometry…) within houdini. But best thing would be to have the effect directly working on a shader so it can work with displacement maps.

Is this a bit clearer now? ops:

ps: I looked for AutoVC but could not find it…

Attachments:
cavity_exemple.jpg (64.2 KB)

JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
941 posts
Joined: July 2005
Offline
jrgauthier
Well, I guess Zbrush does it at the geometry level, but it as so many polygones that it doesn't show. I did a test for myself in Zbrush and joined a picture to my post.

It actually seem like cavity shader actual darkens every concave angles…and that's about it! From, what I can see, it doesn't seem to take anything else in account, what do you think? It doesn't seem to bother with the actual size of the cavity.
Yeah, that just looks like point coloring based on normal curvature (just darkening the negative values). AFAIK, the MeasureSOP doesn't calculate signed normal curvature (actually, I'm not sure which type of curvature it calculates), so here's a vex fragment to calculate normal curvature on a mesh:


// …. Inside a vex SOP ….
vector pi,ni,tid;
vector n = normalize(N);
vector t = { {0} }; // needs initializer else spews warning
int pts = getneighbours(ptnum,0);
int nn = arraylength(pts);
resize(t,nn);

float kn = 0; // this will hold the normal curvature (signed)
int i;
for(i=0;i<nn;i++) {
if(import(“P”,pi,0,pts) && import(“N”,ni,0,pts)) {
ni = normalize(ni);
vector dp = pi-P;
t = normalize(dp - dot(dp,n)*n);
float ki = dot(dp,ni-n) / dot(dp,dp);
if(abs(ki)>abs(kn)) { kn = ki; tid = t; }
}
}

Once you have the normal curvature (the variable “kn” in the above), you can do whatever you want. Here we're interested in the concave bits, and these show up as negative values for kn. So you can shape it with something like what I posted before, controlled by the user through a couple of parameters (“strength” and “rate” in this case):


float strength = 1; // user parameter: “Darkening Strength”
float rate = 1; // user parameter: “Darkening Rate (or Gamma)”
// Now shape the darkening of the cavity with those two parms:
float output = pow(exp(strength*min(0,kn)),rate);


The shaping can be done in a million different ways; that's just one possibility.

Still… for all of this stuff to have enough visual definition you have to apply it to a very dense mesh, which is not going to be a real-time thing – especially if implemented in VEX. Zbrush is very likely doing it as it calculates the geometry, which is very little overhead. All of which brings me to…

Now Mario, sorry for the confusion. When I talk about cavity maps, is that you can actually extract a “cavity map” from zbrush, so zbrush renders out an unfolded cavity texture to use outside zbrush, but it can be heavy you know. I would prefer to be able to generate the effect directly on my shader(or geometry…) within houdini.

How big could this map be? Whatever it is, I have trouble believing that it would be bigger than some monstrously dense chunk of geometry with all kinds of attributes, no?

Anyway… hope that helps.

Oh. Attached is a hip file with the above code stuffed inside a VopSop and the resulting image. If you turn this into an HDA, please post it to the Exchange so others can use it.


This particular algorithm comes from the paper “Curvature Estimation On Triangular Mesh”, by Dong Chen-Shi and Wang Guo-Zhao, and is available here [zju.edu.cn]. The above vex fragment only calculates the curvature portion, not the principal directions. To continue the calculation, the values in the array t are needed; that's the only reason I'm keeping them around – if you're only computing kn, then get rid of the array.

Attachments:
cavity.jpg (31.8 KB)
Cavity.hip (203.8 KB)

Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
12433 posts
Joined: July 2005
Offline
Mario Marengo
How big could this map be? Whatever it is, I have trouble believing that it would be bigger than some monstrously dense chunk of geometry with all kinds of attributes, no?

Hi Mario,

Great shader snippet! Always the best quality meat from you!

What I've been told is that ZBrush uses some kind of level-set definition for all it's internal storage (as opposed to regular mesh) and only creates meshes for openGL display and output. If this is true, this makes it pretty easy to extract displacement maps at different levels of detail using pretty simple level-set operations and, naturally, pretty easy to sculpt upon. I can see it being easy to take the normal curvature of a level-set too.

Perhaps the level-set is an a multiresolution or sparse format - which would account for the awesome amount of detail it can store. However, uv's, I have no idea… I would doubt it uses the octree-style 3d texture format (IIRC ILM presented that one year at SIGGRAPH). I've never used it myself -if that isn't painfully obvious

Take care,
Jason
Jason Iversen, Technology Supervisor & FX Pipeline/R+D Lead @ Weta FX
also, http://www.odforce.net [www.odforce.net]
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Wow Mario, this is just awesome!!!!
I'm nowhere near the level you are in houdini, but this kind of trick is making me crazy…I want to know everything!!

Thanks to Jason also for digging into the subject as well! And everybody else too!

I'm going to try that for sure.

How big could this map be? Whatever it is, I have trouble believing that it would be bigger than some monstrously dense chunk of geometry with all kinds of attributes, no?

Usually it will be around 4k…you might be right on this one. Maybe it's my experience with other renderers(mentalray in maya) that makes me want to avoid an overuse of highres images… I guess the real thing would be able to use this directly at render time, so it works directly with subdivision surfaces and displacement maps…


In the meantime, I achieved a semi cavity effect using the group sop…
just using the edge angle options…not as impressive for sure… ops:
It puts color into cracks, but also color convexe faces with the chosen angle…it doesn't seem to care if the angle is concave or convexe…

Anyways, I'll totally check out carefully what you posted Mario. Thanks you so much!

take care!

Attachments:
semi_cavity_effect.jpg (177.1 KB)
semi_cavity_effect.hipnc (969.9 KB)

JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
941 posts
Joined: July 2005
Offline
Thanks for the insight, Jason. The level-set thing makes sense, and as you say, their trick is no doubt in the economy of their internal representation – from there they can spew out as densly a mesh as OGL can handle. And… as I'm sure is equally painfully obvious, I have never used Zbrush either

@jrgauthier: That's a cool idea with the grouping, but as you noticed, it won't be able to discriminate between concave and convex curvatures. For a similar, but probably cheaper, version of that, check out the Measure SOP – set it to measure curvature and color your points based on that. But, this is a different kind of curvature than what I posted (at least I *think* so), so you'll still have trouble distinguishing between covex/concave (but it's probably faster than grouping). Check it out.

jrgauthier
Usually it will be around 4k…
I wouldn't worry then. Mantra can handle multiple 4k maps very efficiently. Just remember to convert them into .rat files to help out with filtering, that's all.

I was in a rush last night and left a bit of debris when I copied that code. The original keeps going after that, but here we just want the curvature. So to avoid confusion, here it is again with the unused stuff removed, and with some comments:

// …. Inside a vex SOP ….
vector n = normalize(N); // normal of current point
int pts = getneighbours(ptnum,0); // point numbers of all neighbours
int nn = arraylength(pts); // the number of neighbours

vector pi,ni; // these will hold position and normal of each neighbour
float kn = 0; // this will hold the normal curvature (signed)
int i; // the iteration counter
for(i=0;i<nn;i++) {
// Input geometry *must* have normals calculated
if(import(“P”,pi,0,pts) && import(“N”,ni,0,pts)) {
ni = normalize(ni); // normal of current neighbour
vector dp = pi-P; // position differential
float ki = dot(dp,ni-n) / dot(dp,dp); // curvature relative to curr neighbour
if(abs(ki)>abs(kn)) kn = ki; // …which we store if bigger tan last
}
}
// kn now holds the largest absolute curvature value in the
// one-ring neighbourhood of P. Its range is . A
// value of zero means no curvature. Negative values denote
// concavities and positive values convexities.

Cheers!
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Thanks Mario!
I will dig into your code.
I totally need to learn shaders coding!!

I took a look at the measure sop but couldn't make it work properly, I'm missing something here, could you give me a hand(I asked alot already did I ops: ?) I attached a test file to this email…I don't know if it's the measure sop setting I don't put right or where I connect it… I'm just confused…. :cry:
JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
941 posts
Joined: July 2005
Offline
jrgauthier
T
I took a look at the measure sop but couldn't make it work properly, I'm missing something here, could you give me a hand(I asked alot already did I ops: ?) I attached a test file to this email…I don't know if it's the measure sop setting I don't put right or where I connect it… I'm just confused…. :cry:

It seems you forgot to attach the file.
Anyway, when you set the Measure SOP to measure curvature (Type->Curvature), it creates a point attribute (float) called “curvature”. You can use the values of this attribute to color your points. That's it.

But I also mentioned that the Measure SOP will have the same limitations as your group-by-angle approach: That is, it will also fail to distinguish between concave and convex curvature. In other words… like the grouping method, it won't solve your problem (but it will probably be more efficient at failing )

So now it's my turn to be confused… I already gave you a solution that does what you want. Just copy-paste the VopSop that's inside the hipfile that I posted. That's all you need to do. You don't need to understand the code, just use the VopSop as-is. Feed your geometry into it and presto!… instant “cavity shading”. I realize it's not a pretty HDA and all (real men use VopSops ), but it should still work.

P.S: If I get a chance this weekend, I'll turn it into a SOP HDA for you, but again, you can use it as a VopSop just as easily.

Cheers.
Mario Marengo
Senior Developer at Folks VFX [folksvfx.com] in Toronto, Canada.
User Avatar
Member
511 posts
Joined:
Offline
Hi guys,

Looking at this site gave me an idea:
http://www.tomcowland.com/mentalray/tc_curvature/index.html [tomcowland.com]

My implementation (btw im sure the gather stuff is incorrect/incomplete) is basically the dot product of blurred vs un-blurred normals. With some noise affecting some parms. Would be really cool to get some streaky stuff under the overhangs… but I leave that for someone who didn't think math books were for coloring in




Hip attached

cheers
S
Edited by - Nov. 22, 2008 16:24:39

Attachments:
DirtPass.jpg (48.4 KB)
Lit.jpg (48.4 KB)

User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Hi Mario,
Thanks alot for the vop sop you provided! And don't be confused!
Of course what you provided is exactly what I wanted! And I thank you for that!

But, I'm a curious person, so I just wanted to make a quick test with the measure sop as you suggested but failed miserably! All of this, totally understanding that the measure sop wouldn't solve my problem…but I just wanted to play around with it since I never really used it before…

Also, I understand that I don't need to understand the code behind the vop sop, but I think it's really interesting and wish to learn more about coding.

Hoping that all confusions are behind us now!

Thanks alot Mario!


—————————

Hey Serg!! Thanks alot for your post!
Really interesting stuff! I'll have a closer look!

Cheers!

Attachments:
measure_test_failed.hipnc (42.5 KB)

JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
511 posts
Joined:
Offline
dirty bunny



Something is very wrong with the gather setup though… for some reason the render slows down a lot if I add an illumination model to the shader. For example, it takes 24s to render just the dirt pass, and just 1s to render a lighting model, put the two together though and it takes 46s, use the dirt for bump and it takes 1m6s. Add occlusion to the lighting and it gets a LOT worse (more than 10 min)… even though the 64 sample occ pass by itself takes only 8s… hmmm
I dont get it, I've told the gather vop to import an exported parameter than I name “Normal”, nothing else.

Attachments:
Dirtybunny.jpg (46.0 KB)

User Avatar
Member
243 posts
Joined: Oct. 2007
Offline
Serg, this is a really amazing shader!
Can be really really useful!

I tryed to asign it to a new model I built…a plane with a mountain sop + a facet sop to generate normal…but it won't render it out…the render won't start, thought your teapot renders fine…


Sorry can't help you with your rendertime problems thought
JR Gauthier
Character Animation & Design
www.turboatomic.com
http://www.vimeo.com/user2847970 [vimeo.com]
User Avatar
Member
511 posts
Joined:
Offline
Hi There,

Sorry I forgot to mention you must add the “refract limit” render property to your object, and set it to 1.

This is because I don't know how to set the “ray style” like you can when using the Gather call in vex language.
Ray style tells mantra that the ray is refractive/reflective/diffuse… unfortunately the Gather VOP doesnt have this option (amonst others). Besides the vop node being completely undocumented I suspect it's also unfinished.

cheers

S
  • Quick Links