如何从传入矢量和表面法线找到折射矢量?

use*_*239 4 java raytracing vector

我正在用 java 编写光线追踪器,并尝试实现折射,但我对在该主题上找到的信息感到困惑。如果我有入射光线的 3D 矢量、以 3D 矢量形式给出的表面法线以及两种介质的折射率,我需要应用哪些操作才能获得透射光线的矢量?

Ver*_*ahn 7

Bram de Greve 写了一篇关于光线追踪中的反射和折射的好文章。你可以在这里找到它。

他的实现(C++)如下所示:

Vector refract(const Vector& normal, const Vector& incident, 
               double n1, double n2) 
{
    const double n = n1 / n2;
    const double cosI = -dot(normal, incident);
    const double sinT2 = n * n * (1.0 - cosI * cosI);
    if(sinT2 > 1.0) return Vector::invalid; // TIR
    const double cosT = sqrt(1.0 - sinT2);
    return n * incident + (n * cosI - cosT) * normal;
}
Run Code Online (Sandbox Code Playgroud)

以下是 PBRTv3 实现(在 BSD-2-Clause 许可下):

inline bool Refract(const Vector3f &wi, const Normal3f &n, Float eta,
                    Vector3f *wt) {
    // Compute $\cos \theta_\roman{t}$ using Snell's law
    Float cosThetaI = Dot(n, wi);
    Float sin2ThetaI = std::max(Float(0), Float(1 - cosThetaI * cosThetaI));
    Float sin2ThetaT = eta * eta * sin2ThetaI;

    // Handle total internal reflection for transmission
    if (sin2ThetaT >= 1) return false;
    Float cosThetaT = std::sqrt(1 - sin2ThetaT);
    *wt = eta * -wi + (eta * cosThetaI - cosThetaT) * Vector3f(n);
    return true;
}
Run Code Online (Sandbox Code Playgroud)

请参阅我的博客如何实现测试驱动。

  • 这是一个非常有用的遮阳篷,尽管我必须编写 cosI = abs(dot(normal, event)) 才能使其正常工作。 (2认同)