Vec6f GatherTreeBuilder::_ComputeKdPoint( mdGatherPoint &gp )
  {
    CompositedBRDF brdfs;
    // isect.Ns is modified in the shade function although it has been already set
    Vector3f ns = gp.isect.Ns;
    if (gp.isect.material) gp.isect.material->shade(Ray(), Medium::Vacuum(), gp.isect, brdfs);
    gp.isect.Ns = ns;
    float n=0;
    Color kd(zero),ks(zero);
    brdfs.getPhong(kd,ks,n);

    Vector3f direction;
    if (ks!=zero && n!=0.0f)
    {
      float scale = 0.0f;
      if(n < 20.0f)
        scale = 1.0f;
      else if(n < 40.0f)
        scale = 2.0f;
      else if(n < 80.0f)
        scale = 3.0f;
      else
        scale = 4.0f;
      direction =  (- gp.wo + gp.isect.Ns* 2*dot(gp.wo, gp.isect.Ns) ) * scale * _normalScale;
    }
    else
      direction = gp.isect.Ns * _normalScale;

    return Vec6f(gp.isect.P, direction);
  }
  GatherNode* GatherTreeBuilder::_MakeLeaf( vector<GpKdItem>::iterator it, vector<mdGatherPoint> &points)
  {
    GatherNode *node = new GatherNode();
    mdGatherPoint &gp = points[it->idx];
    // the shading normal has been already computed, so restore it
    Vector3f ns = gp.isect.Ns;
    CompositedBRDF brdfs;
    if (gp.isect.material) gp.isect.material->shade(Ray(), Medium::Vacuum(), gp.isect, brdfs);
    gp.isect.Ns = ns;
    float n=0;
    Color kd(zero),ks(zero);
    brdfs.getPhong(kd,ks,n);

    node->gp = &gp;
    node->strength = 1.0f / _samples;
    node->hasGlossy = false;
    node->bbox = BBox3f(gp.isect.P, gp.isect.P);
    node->emission = gp.emission;
    node->kd = kd;
    node->ks = ks;
    node->n = n;

    if(zero != kd)
      node->normalCone = FastConef(gp.isect.Ns);
    if (zero != ks && n > 0.0f)
    {
      node->hasGlossy = true;
      node->mirrorCone =  FastConef(- gp.wo + gp.isect.Ns* 2*dot(gp.wo, gp.isect.Ns) );
    }
    return node;
  }