PBRT笔记(8)——材质

BSDF类

表面着色器会绑定场景中每一个图元(被赋予了这个着色器),而表面着色器则由Material类的实例来表示。它会拥有一个BSDF类对象(可能是BSSDF),用于计算表面上每一点的辐射度(颜色)。

BSDF代表了BRDFs与BTDFs的集合。BSDF构造函数接受一个SurfaceInteraction对象,该对象包含关于表面上任意一点的微分几何信息,以及一个参数eta,该参数给出了边界上的相对折射率。对于不透明的表面,该参数则无效。构造函数将使用着色法线来构造一个正交坐标系。本节中ns表示着色法线(法线贴图上对应坐标的值)和ng代表了几何法线(面法线)。

BSDF存储了最多8个BxDF组件,因为在pbrt中不需要更多组件。BSDF实现了BxDFs坐标系与世界坐标系转换的方法。WorldToLocal(const Vector3f &v)与LocalToWorld(const Vector3f &v)。

着色法线与几何法线的冲突问题

实际渲染的过程中着色法线可能会发生如图9.2这样的漏光现象情况,也就是说直接计算出得到错误的光线遮挡关系。解决方法是:使用几何法线来决定是计算反射还是计算透射,如果ωi与ωo在同一个几何法线的半球,计算BRDFs,不然则计算BTDFs。与上一步不同,在计算散射方程时,法线和入射方向的点积仍然是用着色法线而不是几何法线来处理的。

首先将向量从世界坐标系转换为BSDF坐标系,然后决定是使用BRDFs还是BTDFs。然后循环遍历适当的集合并计算它们的辐射度贡献之和。

Spectrum BSDF::f(const Vector3f &woW, const Vector3f &wiW,
                 BxDFType flags) const {
    ProfilePhase pp(Prof::BSDFEvaluation);
    Vector3f wi = WorldToLocal(wiW), wo = WorldToLocal(woW);
    if (wo.z == 0) return 0.;
    bool reflect = Dot(wiW, ng) * Dot(woW, ng) > 0;
    Spectrum f(0.f);
    for (int i = 0; i < nBxDFs; ++i)
        if (bxdfs[i]->MatchesFlags(flags) &&
            ((reflect && (bxdfs[i]->type & BSDF_REFLECTION)) ||
             (!reflect && (bxdfs[i]->type & BSDF_TRANSMISSION))))
            f += bxdfs[i]->f(wo, wi);
    return f;
}

Material类

Material的派生类必须实现ComputeScatteringFunctions();该函数获取一个SurfaceInteraction对象,该方法用于确定反射属性,并且初始化相应的SurfaceInteraction::BSDF,如果包含了次表面散射,那SurfaceInteraction::BSSRDF也会被初始化。另外几个形参别分是:所使用的内存池引用,透射模式,是否使用多层复合材质的BxDFs(类似车漆这种),之后SurfaceInteraction的实例会调用这个函数进行渲染。

void SurfaceInteraction::ComputeScatteringFunctions(const RayDifferential &ray,MemoryArena &arena,bool allowMultipleLobes,TransportMode mode) {
    ComputeDifferentials(ray);
    primitive->ComputeScatteringFunctions(this, arena, mode,
                                          allowMultipleLobes);
}

金属材质

kd为漫反射值,sigma为粗糙度值。如果sigma为0,即为兰伯特材质,不然就使用OrenNayar模型,另外还有一个凹凸贴图指针变量,在其有效的情况下,用与着色法线的计算。

void MatteMaterial::ComputeScatteringFunctions(SurfaceInteraction *si,MemoryArena &arena,TransportMode mode,bool allowMultipleLobes) const {
    if (bumpMap) Bump(bumpMap, si);
    
    si->bsdf = ARENA_ALLOC(arena, BSDF)(*si);
    Spectrum r = Kd->Evaluate(*si).Clamp();
    Float sig = Clamp(sigma->Evaluate(*si), 0, 90);
    if (!r.IsBlack()) {
        if (sig == 0)
            si->bsdf->Add(ARENA_ALLOC(arena, LambertianReflection)(r));
        else
            si->bsdf->Add(ARENA_ALLOC(arena, OrenNayar)(r, sig));
    }
}

塑料材质

塑料可以被建模为漫反射和光泽散射函数的混合物,参数控制特定的颜色和高光尺寸。塑料材质的参数为Kd和Ks,分别控制漫反射和高光的量。

reaproughness为控制粗糙度效果的变量,如果remapRoughness参数为true,那么roughness将会映射到0~1范围,其中粗糙度值越高,高光亮点越大。如果为false,那么粗糙度直接初始化microfacet分布的参数α(8.4.2的内容)

void PlasticMaterial::ComputeScatteringFunctions(
    SurfaceInteraction *si, MemoryArena &arena, TransportMode mode,
    bool allowMultipleLobes) const {
    // Perform bump mapping with _bumpMap_, if present
    if (bumpMap) Bump(bumpMap, si);
    si->bsdf = ARENA_ALLOC(arena, BSDF)(*si);
    // Initialize diffuse component of plastic material
    Spectrum kd = Kd->Evaluate(*si).Clamp();
    if (!kd.IsBlack())
        si->bsdf->Add(ARENA_ALLOC(arena, LambertianReflection)(kd));

    // Initialize specular component of plastic material
    Spectrum ks = Ks->Evaluate(*si).Clamp();
    if (!ks.IsBlack()) {
        Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.5f, 1.f);
        // Create microfacet distribution _distrib_ for plastic material
        Float rough = roughness->Evaluate(*si);
        if (remapRoughness)
            rough = TrowbridgeReitzDistribution::RoughnessToAlpha(rough);
        MicrofacetDistribution *distrib =
            ARENA_ALLOC(arena, TrowbridgeReitzDistribution)(rough, rough);
        BxDF *spec =
            ARENA_ALLOC(arena, MicrofacetReflection)(ks, distrib, fresnel);
        si->bsdf->Add(spec);
    }
}

混和材质

存储了2个材质的指针,以及一个缩放参数。

void MixMaterial::ComputeScatteringFunctions(SurfaceInteraction *si,MemoryArena &arena,TransportMode mode,bool allowMultipleLobes) const {
    // Compute weights and original _BxDF_s for mix material
    Spectrum s1 = scale->Evaluate(*si).Clamp();
    Spectrum s2 = (Spectrum(1.f) - s1).Clamp();
    SurfaceInteraction si2 = *si;
    m1->ComputeScatteringFunctions(si, arena, mode, allowMultipleLobes);
    m2->ComputeScatteringFunctions(&si2, arena, mode, allowMultipleLobes);

    // Initialize _si->bsdf_ with weighted mixture of _BxDF_s
    int n1 = si->bsdf->NumComponents(), n2 = si2.bsdf->NumComponents();
    for (int i = 0; i < n1; ++i)
        si->bsdf->bxdfs[i] =
            ARENA_ALLOC(arena, ScaledBxDF)(si->bsdf->bxdfs[i], s1);
    for (int i = 0; i < n2; ++i)
        si->bsdf->Add(ARENA_ALLOC(arena, ScaledBxDF)(si2.bsdf->bxdfs[i], s2));
}

除此之外的材质

PBRT还实现了一些别的材质,其实现代码都在materials目录中。

  1. GlassMaterial
  2. MetalMaterial
  3. MirrorMaterial
  4. SubsurfaceMaterial
  5. TranslucentMaterial
  6. UberMaterial
posted @ 2019-03-20 10:14  湛蓝玫瑰  阅读(552)  评论(0编辑  收藏  举报