自定义问题中奇怪的直接照明

weird direct illumination in custom problem

我目前正在实现一个自定义光线追踪渲染器,我坚持直接照明的问题 这是我的结果:

normalOnLight

sphereNormal

max(normalOnLight.dot(sphereNormal), 0.0)

我不明白最后的结果,我认为第一个和第二个是正确的但不是最后一个(点..) 灯光是点光源。

    const Vec4<double> LambertianSampler::radiance(const Ray& ray, const Scene& scene) const
  {
     Context ctx;
     ctx.setCamtoWorld(scene.getCamera()->getLookAt());
     Vec4<double> maxColor(1.0, 1.0, 1.0, 1.0);
     Vec4<double> ambient(0.4, 0.4, 0.4, 1.0);

     Vec4<double> finaleRadiance = ambient;
     for(const auto & light : scene.getLights())
     {
       for(const auto & shape : scene.getShapes())
       {
          shape->intersect(ray, ctx);
       }

      if(ctx.intersectionFound())
      {
      Vec3<double> lightPosition = light->getPos();
      Vec4<double> lightColor    = light->getRadiance();
      Vec3<double> lightNormal   = ctx.getPoint() - lightPosition;
      lightNormal = Vec3<double>(std::fabs(lightNormal.x()), std::fabs(lightNormal.y()), std::fabs(lightNormal.z()));
      lightNormal.normalize();

      Vec3<double> sphereNormal = ctx.getNormal();
      sphereNormal   = Vec3<double>(std::fabs(sphereNormal.x()), std::fabs(sphereNormal.y()), std::fabs(sphereNormal.z())) ;
      sphereNormal.normalize();

      double dot     = lightNormal.dot(sphereNormal);
      finaleRadiance = maxColor*std::max(0.0,dot);
      finaleRadiance = Vec4<double>(finaleRadiance.x(), finaleRadiance.y(), finaleRadiance.z(), 1.0);

      //finaleRadiance = Vec4<double>(sphereNormal.x(), sphereNormal.y(), sphereNormal.z(), 1.0);
      //finaleRadiance = Vec4<double>(lightNormal.x(), lightNormal.y(), lightNormal.z(), 1.0);

    }
  }
  return finaleRadiance;
}

我的打点结果对吗?因为我认为我的 lightNormalOnSphere 和 sphereNormal 是正确的我认为 ..

我通过替换 :

解决了我的问题
lightNormal = Vec3<double>(std::fabs(lightNormal.x()), std::fabs(lightNormal.y()), std::fabs(lightNormal.z()));

来自

lightNormal = Vec3<double>((lightNormal.x()+1)*0.5, (lightNormal.y()+1)*0.5, (lightNormal.z()+1)*0.5);

主要问题在这里:

  Vec3<double> sphereNormal = ctx.getNormal();
  sphereNormal   = Vec3<double>(std::fabs(sphereNormal.x()), std::fabs(sphereNormal.y()), std::fabs(sphereNormal.z())) ;
  sphereNormal.normalize();

但上面的解决方案似乎不太正确。首先,您不必重新规范化球体法线。 fabs 调用将改变一些符号,但幅度 none,因此额外的规范化只是在浪费时间。

但是为什么 fabs 调用。我猜你添加了那是因为球体法线似乎指向了错误的方向。因此,当您采用点积时,您会在较轻的一侧得到负值。您添加了 fabs,这恰好将球体法线 所有 转向光,甚至是黑暗面的法线。这就是为什么您会看到开始出现阴影,但随后光线会逐渐恢复而不是完全变暗的原因。

这也解释了为什么您提出的解决方案似乎有效。您将法线偏向(我认为)您放置灯光的位置。

如果我的理论是正确的,那么您需要翻转球体法线,使它们指向外而不是指向球体。一种快速检查的方法是从交点减去球体的中心,这应该给你一个指向外的矢量,然后你可以对其进行归一化。如果这与您当前正在计算的球体法线不匹配(具体来说,如果符号全部翻转),我的理论将得到证实。

在那种情况下,解决方案就是在计算点积之前翻转球体。

最后,您在灯光上循环,但仅使用列表中最后一个灯光的贡献。 (很难准确判断,因为问题中有一些不匹配的括号。)