我目前正在研究raytracer,只是为了好玩,我在折射处理方面遇到了麻烦。

整个raytracer的代码源可以在on Github中找到。编辑:该代码已迁移to Gitlab

这是渲染的图像:

c++ - 如何正确处理光线追踪中的折射-LMLPHP

右球体的折射率设置为1.5(玻璃)。

除了折射之外,我还想处理一个“透明度”系数,其定义如下:

  • 0->对象为100%不透明
  • 1->对象是100%透明的(没有任何原始对象颜色的痕迹)

    此 Realm 的透明度为1。

    这是处理折射部分的代码。可以找到on github here
    Color handleTransparency(const Scene& scene,
                             const Ray& ray,
                             const IntersectionData& data,
                             uint8 depth)
    {
      Ray refracted(RayType::Transparency, data.point, ray.getDirection());
      Float_t eta = data.material->getRefraction();
    
      if (eta != 1 && eta > Globals::Epsilon)
        refracted.setDirection(Tools::Refract(ray.getDirection(), data.normal, eta));
      refracted.setOrigin(data.point + Globals::Epsilon * refracted.getDirection());
      return inter(scene, refracted, depth + 1);
    }
    
    // http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf
    Float_t getFresnelReflectance(const IntersectionData& data, const Ray& ray)
    {
      Float_t n = data.material->getRefraction();
      Float_t cosI = -Tools::DotProduct(ray.getDirection(), data.normal);
      Float_t sin2T = n * n * (Float_t(1.0) - cosI * cosI);
    
      if (sin2T > 1.0)
        return 1.0;
    
      using std::sqrt;
      Float_t cosT = sqrt(1.0 - sin2T);
      Float_t rPer = (n * cosI - cosT) / (n * cosI + cosT);
      Float_t rPar = (cosI - n * cosT) / (cosI + n * cosT);
      return (rPer * rPer + rPar * rPar) / Float_t(2.0);
    }
    
    Color handleReflectionAndRefraction(const Scene& scene,
                                        const Ray& ray,
                                        const IntersectionData& data,
                                        uint8 depth)
    {
      bool hasReflexion = data.material->getReflexion() > Globals::Epsilon;
      bool hasTransparency = data.material->getTransparency() > Globals::Epsilon;
    
      if (!(hasReflexion || hasTransparency) || depth >= MAX_DEPTH)
        return 0;
    
      Float_t reflectance = data.material->getReflexion();
      Float_t transmittance = data.material->getTransparency();
    
      Color reflexion;
      Color transparency;
    
      if (hasReflexion && hasTransparency)
      {
        reflectance = getFresnelReflectance(data, ray);
        transmittance = 1.0 - reflectance;
      }
    
      if (hasReflexion)
        reflexion = handleReflection(scene, ray, data, depth) * reflectance;
    
      if (hasTransparency)
        transparency = handleTransparency(scene, ray, data, depth) * transmittance;
    
      return reflexion + transparency;
    }
    
    Tools::Refract只是在内部调用glm::refract。 (以便我可以根据需要轻松更改)

    我不处理n1n2的概念:空气中n2始终被视为1。

    我在误解一些明显的东西吗?

    编辑

    在添加了一种方法来了解射线是否在对象内部之后(如果是,则否定了法线),我得到了:

    c++ - 如何正确处理光线追踪中的折射-LMLPHP

    在四处寻找帮助时,我偶然发现了this帖子,但我认为答案无法解决任何问题。通过阅读它,我根本不明白我应该做什么。

    编辑2

    我已经尝试了很多事情,目前我正在:

    c++ - 如何正确处理光线追踪中的折射-LMLPHP

    更好,但我仍然不确定是否正确。我以这张图片为灵感:

    c++ - 如何正确处理光线追踪中的折射-LMLPHP

    但这是使用两个折射率(为了更接近现实),而我想简化并始终将空气视为第二(进出) Material 。

    我在代码中进行的本质更改是在这里:
    inline Vec_t Refract(Vec_t v, const IntersectionData& data, Float_t eta)
    {
      Float_t n = eta;
    
      if (data.isInside)
        n = 1.0 / n;
      double cosI = Tools::DotProduct(v, data.normal);
    
      return v * n - data.normal * (-cosI + n * cosI);
    }
    

    这是相同 Realm 的另一种观点:

    c++ - 如何正确处理光线追踪中的折射-LMLPHP

    最佳答案

    编辑:我认为这个以前的版本并不完全正确,所以我编辑答案。

    阅读所有注释,问题的新版本并自己做一些实验后,我生成了以下版本的refract例程:

    float3 refract(float3 i, float3 n, float eta)
    {
        eta = 2.0f - eta;
        float cosi = dot(n, i);
        float3 o = (i * eta - n * (-cosi + eta * cosi));
        return o;
    }
    

    这次调用它不需要任何其他操作:
    float3 refr = refract(rayDirection, normal, refrIdx);
    

    我仍然不确定的唯一一件事是进行内部光线相交时折射率的反转。在我的测试中,无论是否反转索引,生成的图像都没有太大差异。

    下面是一些具有不同索引的图像:

    c++ - 如何正确处理光线追踪中的折射-LMLPHP
    c++ - 如何正确处理光线追踪中的折射-LMLPHP

    有关更多图像,请参见link,因为该站点不允许我在此处放置更多图像。

    关于c++ - 如何正确处理光线追踪中的折射,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42218704/

  • 10-13 08:25