Bevel shader

Very significant progress Varkenvarken… the bevels on the bottom side of the cubes have something strange, somehow, though. But, nevertheless, it seems that the whole thing is already very near to a solution. :slight_smile:

Piotr… I tried your code too but I did not be able to have a result. It only gave some ao like shading in the areas of the indented edges of the object (I tried it with my boolean cubes mesh). Can you put some node setting screenshot?

When you make your experiments keep in mind, please, not to render only with glossy shading but with simple diffuse shading too… because it seems that there it is where the results of the shading reveal, mainly, its working quality.

But I did render with a diffuse shader, and the node setup is posted right in the screenshot… The AO like shading is in fact AO because you probably tried to connect the color output to something. The shader can output AO for nearly free in the same pass, so I included it. Also make sure you set the mode. Mode 0 is for concave areas, mode 1 is for convex, and mode 2 is for both.

Btw, let say this too: if we had a small ‘select all sharp corners’ add-on too (so that someone may select at once and bevel actually the many corners of such an object as the one I attached) then, in combination with a good bevel shader there could be achieved near perfect results in even such complex objects. Although such a small add-on may be quite useful -especially if it has a selection by sharpness degree- independently of the bevel shading too.

Varkenvarken it seems that you like such ideas (it is evident from the work you have done in your blog), so I do find the courage to share the idea… :slight_smile:

Piotr sorry, I focused only on the code and forgot that the screenshot too was there… going to test it again… :slight_smile:

Read the friendly manual. Select sharp is a core function.
http://i.imgur.com/3MlwDt6.png

I know this function but I do not mean selecting the sharp edges but the sharp corners… the thing that I did mean is an add-on which will select only the sharp corners, so that they may be bevelled independently of the edges. Because in such boolean structures, as the one I did attach, the topology does not permit producing good bevelling on the edges of the object… although its corners if selected easily at once they may be bevelled without any problem. :slight_smile:

You mean like the Vertex Only option for bevel?

Yes, but for only the sharp corner constituting vertexes of an object…

So select sharp edges, then bevel vertex only :stuck_out_tongue:

Anyway, this is off topic.

Piotr, I tried your shading settings too… in some areas of the object they give very nice results while in some other areas they do produce problems… below is the result of my try, as you see there are contours around -and even inside- the objects here and there:

http://i1272.photobucket.com/albums/y390/Cloudydaylover/3Dworks/Bevelshadingexpglossy_zps55d2c821.png

If you select sharp edges there become selected all the vertexes along the selected edges… the needed thing is to select only the corner edges however… :slight_smile:

I guess I could reject the ray if the normal is pointing away from the camera… Anybody know how to get the camera vector without plugging in a node?

Edit: Nevermind. The incident ray was what I wanted. Here’s the updated version:


void rng_seed(output int rng, int seed)
{
  int chash = seed;
  if (chash == 0) chash = 1;
  rng = chash * 30391861;
}

float rng_uniform(output int rng)
{
  float res = rng / float(2137483647) * 0.5 + 0.5;
  rng *= 30391861;
  return res;
}

void to_unit_disk(float x, float y, output float x_out, output float y_out)
{
  float r, phi;
  float a = 2.0 * x - 1.0;
  float b = 2.0 * y - 1.0;
    
  if(a > -b) 
  { if(a > b) 
    { r = a;
      phi = M_PI_4 *(b/a);
    }
    else 
    { r = b;
      phi = M_PI_4 *(2.0 - a/b);
  } }
  else 
  { if(a < b) 
    { r = -a;
      phi = M_PI_4 *(4.0 + b/a);
    }
    else 
    { r = -b;
      if(b != 0.0) phi = M_PI_4 *(6.0 - a/b);
      else phi = 0.0;
  } }
  x_out = r * cos(phi);
  y_out = r * sin(phi);
}

void make_orthonormals(vector N, output vector a, output vector b)
{
  if(N[0] != N[1] || N[0] != N[2]) a = cross(vector(1, 1, 1), N);
  else a = cross(vector(-1, 1, 1), N);
  
  a = normalize(a);
  b = cross(N, a);
}

vector sample_cos_hemisphere(vector N, float randu, float randv)
{
  vector T, B;
    
  make_orthonormals(N, T, B);
  to_unit_disk(randu, randv, randu, randv);
  float costheta = sqrt(max(1.0 - randu * randu - randv * randv, 0.0));

  return randu * T + randv * B + costheta * N;
}

shader node_occlusion2(
  color Effect = color(0),
  color No_Effect = color(1),
  int Mode = 0, /* 0: Concave (AO) 1:Convex (Wear) 2:Both */
  int InvertEffect = 0,
  float Distance = 0.2,
  int Samples = 1,
  output color Color = 0,
  output float Fac = 0,
  output normal outNormal = N
)
{
  int i, rng;
  float f, randu, randv, ray_t, hits = 0;
  vector ray_P, ray_R;
  normal hit_normal = N;
  float hit_dist;

  f = fmod(cellnoise(P*123456.0), 1.0);
  rng_seed(rng, int(f * 21374647));
  
  for(i = 0; i < Samples; i++) 
  { randu = rng_uniform(rng);
    randv = rng_uniform(rng);
       
    ray_P = P;
    ray_R = sample_cos_hemisphere(-N, randu, randv);
    ray_t = Distance;
    
        
    if (!Mode)
    { if(trace(ray_P, -ray_R, "maxdist", ray_t)) {
            hits += 1.0;
            int HitNormal = getmessage ("trace", "N", hit_normal);
            outNormal = outNormal + (hit_normal);
        }
    }
    else if (Mode == 1)
    { if(trace(ray_P, ray_R, "maxdist", ray_t)) {
           hits += 1.0;
           int HitNormal = getmessage ("trace", "N", hit_normal);
           if (dot(I, -hit_normal) > 0.0) outNormal = outNormal - (hit_normal);
        }
    }
    else { 
        if(trace(ray_P, -ray_R, "maxdist", ray_t)) {
            hits += 1.0;
            int HitNormal = getmessage ("trace", "N", hit_normal);
            outNormal = outNormal + (hit_normal);
        }
        if(trace(ray_P, ray_R, "maxdist", ray_t)) {
           hits += 1.0;
           int HitNormal = getmessage ("trace", "N", hit_normal);
           if (dot(I, -hit_normal) > 0.0) outNormal = outNormal - (hit_normal);
        }
    } 
  }
  Fac = 1.0 - (hits/Samples);
  if(InvertEffect) Color = mix(No_Effect, Effect, Fac);
  else Color = mix(Effect, No_Effect, Fac);
  outNormal = normalize(outNormal);
}

Any chance to replicate these experiments without OSL? (aka GPU friendly)

Nope. Not without hacking Cycles.

ok OSL cannot work with these other smooth tools!

but what do you use ?
do you combine effects like using object smooth plus
your bevel shader OSL
or only use bevel shader alone ?

thanks

I’m not sure I understand the question. What other smooth tools? I used simple geometry + edge split.

RickyBlender, a shader like this is an alternative to using the bevel modifier to wear/soften edges. It has nothing else to do with smoothing tools.

It’s more memory friendly since it doesn’t make more polys, plus it can work on some shapes where an actual bevel doesn’t work right due to topology problems. Plus you can stack it straight on top of edge split, which you can’t do quite right with the bevel modifier:


It might be a little slower than the bevel modifier (at least for a floating cube it is), since messing with this shader might be more work than extra triangles.

It’s most definitely more work than extra triangles - this shader actually does its own raytracing, much like AO. On the other hand, it doesn’t suffer from any kind of normal problems, doesn’t distort textures, won’t explode your mesh and is light on memory. And most importantly, will perfectly bevel geometry even if it just intersects - even between separate objects, provided their materials use the same distance and sampling settings.

This is my favorite part of Mental Ray’s round corner shader. You can just intersect some object through the middle of a face on another object, and it will actually round off the edge where they meet.

Piotr, somewhat ignorant question: How hard would it be to have this take an arbitrary incoming normal and just add on to it (using the regular object normals when nothing’s specified). Like the bump node does.

Not very. Give me a few minutes.

Edit: here you go:


void rng_seed(output int rng, int seed)
{
  int chash = seed;
  if (chash == 0) chash = 1;
  rng = chash * 30391861;
}

float rng_uniform(output int rng)
{
  float res = rng / float(2137483647) * 0.5 + 0.5;
  rng *= 30391861;
  return res;
}

void to_unit_disk(float x, float y, output float x_out, output float y_out)
{
  float r, phi;
  float a = 2.0 * x - 1.0;
  float b = 2.0 * y - 1.0;
    
  if(a > -b) 
  { if(a > b) 
    { r = a;
      phi = M_PI_4 *(b/a);
    }
    else 
    { r = b;
      phi = M_PI_4 *(2.0 - a/b);
  } }
  else 
  { if(a < b) 
    { r = -a;
      phi = M_PI_4 *(4.0 + b/a);
    }
    else 
    { r = -b;
      if(b != 0.0) phi = M_PI_4 *(6.0 - a/b);
      else phi = 0.0;
  } }
  x_out = r * cos(phi);
  y_out = r * sin(phi);
}

void make_orthonormals(vector N, output vector a, output vector b)
{
  if(N[0] != N[1] || N[0] != N[2]) a = cross(vector(1, 1, 1), N);
  else a = cross(vector(-1, 1, 1), N);
  
  a = normalize(a);
  b = cross(N, a);
}

vector sample_cos_hemisphere(vector N, float randu, float randv)
{
  vector T, B;
    
  make_orthonormals(N, T, B);
  to_unit_disk(randu, randv, randu, randv);
  float costheta = sqrt(max(1.0 - randu * randu - randv * randv, 0.0));

  return randu * T + randv * B + costheta * N;
}

shader node_occlusion2(
  color Effect = color(0),
  color No_Effect = color(1),
  int Mode = 0, /* 0: Concave (AO) 1:Convex (Wear) 2:Both */
  int InvertEffect = 0,
  float Distance = 0.2,
  int Samples = 1,
  normal Normal = N,
  output color Color = 0,
  output float Fac = 0,
  output normal outNormal = 0
)
{
  int i, rng;
  float f, randu, randv, ray_t, hits = 0;
  vector ray_P, ray_R;
  normal hit_normal = N;
  outNormal = Normal;
  float hit_dist;

  f = fmod(cellnoise(P*123456.0), 1.0);
  rng_seed(rng, int(f * 21374647));
  
  for(i = 0; i < Samples; i++) 
  { randu = rng_uniform(rng);
    randv = rng_uniform(rng);
       
    ray_P = P;
    ray_R = sample_cos_hemisphere(-N, randu, randv);
    ray_t = Distance;
    
        
    if (!Mode)
    { if(trace(ray_P, -ray_R, "maxdist", ray_t)) {
            hits += 1.0;
            int HitNormal = getmessage ("trace", "N", hit_normal);
            outNormal = outNormal + (hit_normal);
        }
    }
    else if (Mode == 1)
    { if(trace(ray_P, ray_R, "maxdist", ray_t)) {
           hits += 1.0;
           int HitNormal = getmessage ("trace", "N", hit_normal);
           if (dot(I, -hit_normal) > 0.0) outNormal = outNormal - (hit_normal);
        }
    }
    else { 
        if(trace(ray_P, -ray_R, "maxdist", ray_t)) {
            hits += 1.0;
            int HitNormal = getmessage ("trace", "N", hit_normal);
            outNormal = outNormal + (hit_normal);
        }
        if(trace(ray_P, ray_R, "maxdist", ray_t)) {
           hits += 1.0;
           int HitNormal = getmessage ("trace", "N", hit_normal);
           if (dot(I, -hit_normal) > 0.0) outNormal = outNormal - (hit_normal);
        }
    } 
  }
  Fac = 1.0 - (hits/Samples);
  if(InvertEffect) Color = mix(No_Effect, Effect, Fac);
  else Color = mix(Effect, No_Effect, Fac);
  outNormal = normalize(outNormal);
}