2

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

正常开灯 在此处输入图像描述

球体正常 在此处输入图像描述

最大值(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 是正确的。

4

2 回答 2

1

我通过替换来解决我的问题:

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);
于 2019-08-15T14:32:24.907 回答
0

主要问题在这里:

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

但是上面的解决方案似乎不太正确。首先,您不必重新标准化球体法线。这些fabs调用将改变一些迹象,但没有一个幅度,所以额外的标准化只是在浪费时间。

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

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

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

在这种情况下,解决方案只是在计算点积之前翻转球体法线。

最后,您将遍历灯光,但仅使用列表中最后一个灯光的贡献。(很难确切地说出来,因为你的问题中有一些不匹配的括号。)

于 2019-08-15T18:50:57.183 回答