You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

路径追踪器玻璃BSDF实现求助:球体边缘出现深色异常

Hey there! Let's work through your glass BSDF implementation and fix that dark edge issue step by step.

First, let's recap why glass is trickier than mirror: it combines specular reflection (like your mirror material) and specular refraction, with the ratio controlled by the Fresnel effect. Dark edges usually come from missing edge cases (like total internal reflection) or incorrect energy scaling in your BSDF calculations.

Common Causes of Dark Edges

Before diving into code, let's list the most likely culprits for your sphere's dark edges:

  • Missing handling of total internal reflection (TIR) (when light exits a dense medium like glass into air at a steep angle, it reflects entirely instead of refracting)
  • Incorrect Fresnel coefficient calculations (edges have near-grazing angles where Fresnel should approach full reflection)
  • Wrong energy scaling for refraction (not accounting for the change in solid angle when light crosses medium boundaries)
  • Refraction direction miscalculations (swapping IOR ratios or messing up normal orientation)

Correct Glass BSDF Implementation

Here's a robust implementation that addresses these issues, with explanations tied to your existing mirror code:

First, add a Fresnel approximation (Schlick's is fast and accurate for most cases):

float SchlickFresnel(float cosTheta, float ior) {
    float r0 = (1.0f - ior) / (1.0f + ior);
    r0 *= r0;
    return r0 + (1.0f - r0) * powf(1.0f - cosTheta, 5.0f);
}

Now, the GlassBSDF f function. Unlike mirror, we need to check if the incoming direction wi is a reflection or refraction direction, then compute the correct contribution:

Spectrum GlassBSDF::f(const Vector3D& wo, const Vector3D& wi) const {
    float cosThetaO = abs_cos_theta(wo);
    bool isEntering = dot(wo, normal) > 0; // Light coming from air into glass?

    // First, check if wi is the specular reflection direction
    Vector3D reflectDir = reflect(wo, normal);
    if (wi == reflectDir) {
        float fresnel = SchlickFresnel(cosThetaO, isEntering ? ior : 1.0f/ior);
        return reflectance * fresnel / cosThetaO;
    }

    // Check if wi is the specular refraction direction
    float etaI = isEntering ? 1.0f : ior;
    float etaT = isEntering ? ior : 1.0f;
    Vector3D refractDir;
    bool canRefract = refract(wo, normal, etaI / etaT, &refractDir);

    // Handle total internal reflection: no refraction possible
    if (!canRefract) {
        return Spectrum(0.0f);
    }

    if (wi == refractDir) {
        float fresnel = SchlickFresnel(cosThetaO, isEntering ? ior : 1.0f/ior);
        float transmittance = 1.0f - fresnel;
        // Scale by eta² to account for solid angle change across mediums
        float etaRatioSq = (etaT / etaI) * (etaT / etaI);
        return reflectance * transmittance * etaRatioSq / cosThetaO;
    }

    // If wi is neither reflection nor refraction, return 0
    return Spectrum(0.0f);
}

Key Fixes for Dark Edges

  1. Total Internal Reflection Handling: The refract function will return false when TIR occurs (e.g., light exiting glass to air at a steep angle). We skip refraction entirely here, ensuring all energy goes to reflection (which matches real-world behavior).
  2. Fresnel Direction Awareness: We adjust the IOR in the Fresnel calculation based on whether light is entering or exiting the glass. At grazing angles (sphere edges), this pushes Fresnel to 100% reflection, eliminating dark spots.
  3. Energy Scaling: The etaRatioSq term fixes the solid angle mismatch when light crosses medium boundaries—without this, refracted light would appear too dim, especially at edges.

Additional Tips

  • Don't forget your BSDF's sampling function (Sample_f): You'll need to randomly choose between reflection and refraction directions weighted by the Fresnel coefficient (e.g., use Russian roulette or direct sampling with proper weighting).
  • Verify your normal orientation: Ensure sphere normals point outward, and your dot checks correctly handle light inside the glass (flipping the normal implicitly via the IOR ratio).

内容的提问来源于stack exchange,提问作者bin guo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:28:27