Monday, October 20, 2014

Bevel shader

есть очень классная штука - рендерит углы не острыми а сглаженными, то есть геометрия остаётся с острыми углами а на рендере они сглажены - очень добавляет реализма. в максе был для этого плагин fedge, в менталрее есть тоже встроенное дело под эту задачу. а в блендере нету.... :( но народ пораскинул мозгами и родил вот что, жаль пока OSL на GPU не работает, но будем надеяться.

http://blenderartists.org/forum/showthread.php?329295-Bevel-shader


сделать текстовый блок, воткнуть его в нод-едиторе материалов в нормаль шейдера. настройки в принципе более менее понятные.

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 edge_smooth(
  int Concave = 1,
  int Convex = 1,
  int Samples = 4,
  int Backfacing = 1,
  float Mask = 1,
  float Distance = 0.1,
  normal Normal = N,
  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;
  float normal_blend;
  float s_weight = 1/Samples;

  f = fmod(cellnoise(P*123456.0), 1.0);
  rng_seed(rng, int(f * 21374647));

    if (Mask > 0.5 && raytype("camera")) {
      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 (Concave == 1)
            { if(trace(ray_P, -ray_R, "maxdist", ray_t)) {
                    getmessage ("trace", "N", hit_normal);
                    getmessage ("trace", "hitdist", hit_dist);
                    normal_blend = 1-(hit_dist/Distance);
                    outNormal = Normal + (hit_normal*normal_blend);
                    break;
                }
            }
            if (Convex == 1) {
                if(trace(ray_P, ray_R, "maxdist", ray_t)) {
                    getmessage ("trace", "N", hit_normal);
                    getmessage ("trace", "hitdist", hit_dist);
                    normal_blend = 1-(hit_dist/Distance);
                    if (Backfacing==1 || dot(I, -hit_normal) > 0.0) {
                        outNormal = Normal - (hit_normal*normal_blend);
                    }
                    break;
                }
            }
      }
    }
  outNormal = normalize(outNormal);
}