Jump to content

rendering open curves

Recommended Posts

I have an curve with a (constant) width attribute. It's displaced into a tube shape. So far it works perfectly, but there are some things I don't understand. You can see both "errors" in the attached picture

Sometimes the tip of the curve gets tapered althought the width attribute is constant, sometimes not. Why does this happen?

Also at the tip the shading looks a bit weird. Near the end there is a sudden loss of luminance. What can I do to prevent this?

Thanks again



Link to comment
Share on other sites

Hey Achim,

Anything else I could try?

I havent looked at the hip, so I could be way off here, but it looks to me like the problem might lie with your shader, and not with how Houdini does RiCurves...

Try rendering the ribbon with a constant shader (i.e: just pump some color to Cf) and see what it looks like. If the ribbon doesn't exhibit any transitional artifacts as it thins out, then the problem is that your shader is not taking filtering into account (anti-aliasing).

Just a thought...


Link to comment
Share on other sites

  • 2 weeks later...
So antialiasing. hmmm, no idea how to do it.

Hey Achim,

Sorry for the delay, but things got a little crazy there for a while.

So I looked at the file, and there are a couple of things that were a little strange, but generally, the problems at the thin end of the strands were due to lack of antialiasing on the shader's part.

Here are some of the main bits:

1. The strands had a double point (two points on top of each other) at the "thick" end. That's why that end was tapering when it shouldn't have.

2. As Mcronin and Edward suggested, you do need to refine the curves, else the rendered curve won't match up. No need to go crazy, but...yes. I wonder if Mantra uses some other spline (instead of NURB or Bezier) and that's why they don't match (?!?) Anyway; linear (i.e: poly-line, matches just fine as you already know).

3. The idea behind RiCurves (sorry, but it's easier to call them that, than "open-polys-rendered-as-ribbons-aligned-to-camera" ;) ), is to use them when the "tube" is meant to be very "thin" (all things being relative). And given that that's the case, you shouldn't really need to resort to actual displacement to give it shape (i.e. you're never going to get so close as to see inside the "tube"). At those scales then, "shape" is just "light". All you really need to do is shade it "as though" it were a tube. Besides; displacements are much more likely to give you some artifacts (as you already found out in this case).

4. Given these tubes are thin -- not "hair thin", but pretty thin nonetheless -- then we can bump instead of displace, and keep everything inside the surface shader. See the hip for details, but basically, we use the implicit equation for a circle. You know 'x' (== parametric 's'), and you know the radius 'r' (== bound attribute 'width'/2); so all you need is 'y' (the "elevation"), like this:

Implicit eqn for circle:
	  x^2 + y^2 = r^2
Solve for y:
  ->  y = sqrt(r^2 - x^2);

just plug into it the known values for r and x:
	  r = width*.5; 
	  x = s*width - r;

Once you know y, you can calculate the "bumped" position Ptube = P+normalize(N)*y. Then the virtual tube's N at Ptube which is Ntube = normalize(dPds)*x + normalize(N)*y. And finally, the new I which is now Itube = Ptube-Eye (instead of its usual P-Eye).

All shading depends on P, N, and I, so once we define the virtual tube's Ptube, Ntube, and Itube, we proceed as usual except we use the tube variants for those three globals.

5. Given that all shading (in this case!) depends on P, N, and I; and given that, for our tube, all those were derived from y which itself is a function of x -> y = f(x[,r]) = sqrt(r^2 - x^2), we should choose that function as a first place to start antialiasing. If you think about it, you'll realize that, as the hair gets thinner and thinner, our x starts jumping from +1 to -1 over less and less space, until at the tip, it covers the whole [-1,+1] range instantaneously.

There are basically two ways to go about the antialiasing. One is to analyze the function and, if possible, come up with a way to integrate its value over the range being sampled. Not all functions can be analyzed like this -- they are the minority in fact. The other way is to "fade" to some known average value as the filter size gets bigger -- this is the method I use in the file (sorry; too lazy to think about the analytical method , although it *does* exist in this case).

OK. this is getting too long. Have a look, and if something makes you go "huh!?!", then ask :)



  • Like 1
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.

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...