Jump to content

Surface curvature


AndrewVK

Recommended Posts

Is it possibly to detect surface curvature

during render time?

I want to know is current sample belongs to

flat/convex/concave part of surface to achieve

this type of data flow:

1 - hill peak.....0 - flat surface....-1 - abyss peak

Currently i can do it by calculating this data as point

attribute with help of vex sop operator and parse

it to shader as a parameter...but this solution does not

works with displacement and require wery dense object.

Any ideas?

Link to comment
Share on other sites

Thaks Daniel.

It seems to suit my needs.

I`ll try it.

Hey Andrew,

I had started translating all that stuff a while back (from PRMan to VEX) and, even though I haven't finished yet, you might find this helpful.

It is basically a test of some of the curvature-related math, wrapped up in the form of a shader -- just a tool to check that what I think should happen actually does. So, for example, it calculates *all* the coefficients that are involved, which, in a "real" shader would be just a waste of cycles, since you just need a few if your doing, say, just Gaussian curvature.

I've named the variables so they match what I found in most of the literature.

My main source was this paper, but there are lots of others - actually, the stuff at mathworld (Wolfram) is really good.

I haven't looked through the Affine code yet, but I'm sure he's using something simmilar -- I'll definitely check it out when I get a chance.

Here's an early VEX test:

// This form of the quad eqn. was taken from 
// [url=http://mathworld.wolfram.com/QuadraticEquation.html]http://mathworld.wolfram.com/QuadraticEquation.html[/url]
// It avoids numerical problems when b^2 > 4ac
void SolveQuad(float a,b,c; export float k1,k2) {
   float q = b*b - 4*a*c;
   if(q<0.) { k1=k2=0.; return; }
   q = -.5 * ( b + (b<0 ? -1. : 1.) * sqrt(q) );
   k1 = q / a;
   k2 = c / q;
}


// Shader: Test Curvature
//-------------------------------------------------------------------
#pragma label lo        "Range: Low"
#pragma label Clo       "Color: Low"
#pragma hint  Clo       color
#pragma label hi        "Range: High"
#pragma label Chi       "Color: High"
#pragma hint  Chi       color
#pragma hint  xtrap     toggle
#pragma label xtrap     "Extrapolate Derivatives"
#pragma hint  ldiff     toggle
#pragma label ldiff     "Use Diffuse Lighting"
#pragma hint  print     toggle
#pragma label print     "Ouput Values to StdOut"
#pragma hint  smooth    toggle
#pragma label smooth    "Smooth Derivatives"
#pragma label ctype     "Curvature Type"
#pragma choice ctype "mean"   "Mean"
#pragma choice ctype "amean"  "Absolute Mean"
#pragma choice ctype "gauss"  "Gaussian"
#pragma choice ctype "min"    "Minimum"
#pragma choice ctype "max"    "Maximum"

surface testCurvature (
   string   ctype = "mean";
   float    lo    =  -1,
            hi    =  1;
   vector   Clo   =  {1,1,0},
            Chi   =  {0,0,1};

   int      ldiff =  0,
            xtrap =  1,
            smooth=  1,
            print =  0;
   )
{
   vector NN = normalize(N);
   float  Result = 0;

   // The needed partials
   vector Xu  = Du(P, "smooth",smooth,"extrapolate",xtrap),
          Xv  = Dv(P, "smooth",smooth,"extrapolate",xtrap),
          Xuu = Du(Xu,"smooth",smooth,"extrapolate",xtrap),
          Xuv = Du(Xv,"smooth",smooth,"extrapolate",xtrap),
          Xvv = Dv(Xv,"smooth",smooth,"extrapolate",xtrap);

   // Coefficients of the first fundamental form   ( I  )
   float E = dot(Xu,Xu), F = dot(Xu,Xv), G = dot(Xv,Xv);

   // Coefficients of the second fundamental form  ( II )
   float e = dot(NN,Xuu), f = dot(NN,Xuv), g = dot(N,Xvv);

   // Coefficients for the quad eq.
   float disc = E*G - F*F;
   float a = (f*F - e*G) / disc,
         b = (g*F - f*G) / disc,
         c = (e*F - f*E) / disc,
         d = (f*F - g*E) / disc;

   // Solve for the Principal Curvatures (Kmin and Kmax)
   float K1,K2;
   SolveQuad(1.,a+d,a*d-c*b,K1,K2);
   float Kmin = min(K1,K2);
   float Kmax = max(K1,K2);

   // Mean: H = (K1+K2)/2 or H = (1/2) ( (eG - sfF + gE) / (EG - F^2) )
   float H = (e*G - 2.*f*F + g*E ) / (2. * disc);

   // Gaussian: K = K1*K2 or K = eg - f^2 / EG - F^2
   float K = (e*g - f*f) / disc;

   // Switch on type
   if(ctype=="mean") {
      Result = H;
   } else if(ctype=="amean") {
      Result = abs(H);
   } else if(ctype=="gauss") {
      Result = K;
   } else if(ctype=="min") {
      Result = Kmin;
   } else if(ctype=="max") {
      Result = Kmax;
   }

   if(print) printf("R: %f, ",Result);

   // Fit to range and false-color by lerping HSV
   Result = fit(Result,lo,hi,0.,1.);
   vector Calb = hsvtorgb(lerp(rgbtohsv(Clo),rgbtohsv(Chi),Result));
   Cf = ldiff ? Calb*diffuse(NN) : Calb;
   Af = 1; Of = 1;

}

And here's a pic showing the "Mean" curvature on a "z += sin(u)^3 * sin(v)^3 " patch:

Curv1.jpg

Link to comment
Share on other sites

Thanks Mario!

You are right, both shaders are based on the same principles.

Thanks for link. It would be hard to get what is going on without this paper.

One more question.

How does the Du() function work in mantra?

"Computes the derivative of the variable with respect

to the s parametric coordinate.

This is the change in the variable over the area being shaded."

Does it mean, that shader launches also for computing values

of the adjacent vertices during shading process of the

current micropolygon's vertex?

Link to comment
Share on other sites

Does it mean, that shader launches also for computing values

of the adjacent  vertices during shading process of the

current micropolygon's vertex?

Well, I know I'm over-simplifying here, but basically: "yes". :blink:

Whether it's just the corners of the patch or more depends on a few things (oversampling being one of them), but yes, the shader will run on every one of those samples. The renderer needs these to integrate the final color.

I think you're thinking that maybe it actually runs at least *twice* per sample -- once for all derivatives, and again for final color. In this respect, I think it's safe to say that it will do everything possible to *not* do that. (whether it succeeds is another story ;) )

Now; every renderer is different, but basically, the shader compiler knows (at compile time) which local variables are varying, and which uniform/constant -- this is obviously useful for things like derivs. The renderer, in turn, knows the values for all the global quantities (s, t, P, N, etc.) for each one of the samples, and it can therefore determine how any one of these change with respect to another (like s and t). It can also, by extension, calculate how any other varying user-variables changes as well.

How you tell the renderer that something is "varying" depends on the renderer. In VEX, you don't -- it makes that determination by itself. In both cases the compiler (vcc or shader) does some heavy work to minimize unnecessary run-time calculations (like running the *whole* shader just to calc a deriv).

In short, if all goes well, then the renderer shouldn't have to cook the *entire* shader (and discard the result) just to calculate some derivative....

And then there's always Murphy... :P

This is how I understand it from reading some stuff and talking to some people. None of it is based on any hard personal experience, so it is only *marginally* more reliable than simply wild speculation. :ph34r:

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