Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

https://github.com/laurent-lu/TMbLM-Rendering
21 October 2023, 05:38:44 UTC
  • Code
  • Branches (1)
  • Releases (0)
  • Visits
    • Branches
    • Releases
    • HEAD
    • refs/heads/main
    No releases to show
  • 522c671
  • /
  • plugins
  • /
  • tm2.cpp
Raw File Download
Take a new snapshot of a software origin

If the archived software origin currently browsed is not synchronized with its upstream version (for instance when new commits have been issued), you can explicitly request Software Heritage to take a new snapshot of it.

Use the form below to proceed. Once a request has been submitted and accepted, it will be processed as soon as possible. You can then check its processing state by visiting this dedicated page.
swh spinner

Processing "take a new snapshot" request ...

Permalinks

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
  • revision
  • snapshot
origin badgecontent badge Iframe embedding
swh:1:cnt:c97db87b2ffe21804be38a9f36f4789b6d36dab6
origin badgedirectory badge Iframe embedding
swh:1:dir:15c9b846643926e0283b9923373032f2f8d50600
origin badgerevision badge
swh:1:rev:26975e6f47f8c0b63f37e5e3f9c90d051ac25209
origin badgesnapshot badge
swh:1:snp:a276e74c1cc68176a285facfb42032a61eefde1b
Citations

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
  • revision
  • snapshot
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Tip revision: 26975e6f47f8c0b63f37e5e3f9c90d051ac25209 authored by Joël Randrianandrasana on 20 September 2021, 14:27:13 UTC
* README: Windows 10 build instructions: Added note related to Mitsuba's GUI issue
Tip revision: 26975e6
tm2.cpp
#include "tm.h"

MTS_NAMESPACE_BEGIN

class TM2 : public BSDF {
private:

    // Layers parameters
    int m_layer_count;

    std::vector<ref<const Texture>> m_tex_etas;
    std::vector<ref<const Texture>> m_tex_kappas;
    std::vector<ref<const Texture>> m_tex_alphas;

    // LUTs
    lut4 m_FGD;
    lut3 m_TIR;

public:

    TM2(const Properties& props): BSDF(props) {

        // Structure properties
        parseLayers(props, m_layer_count, m_tex_etas, m_tex_kappas, m_tex_alphas, true);

        // LUTs
        ref<FileResolver> fResolver = Thread::getThread()->getFileResolver();

        m_FGD = lut4(fResolver->resolve("data/tm_FGD.bin").string());
        m_TIR = lut3(fResolver->resolve("data/tm_TIR.bin").string());
    }
    TM2(Stream* stream, InstanceManager* manager): BSDF(stream, manager) {

        configure();
    }

    void configure() {

        m_components.clear();
        m_components.push_back(EGlossyReflection | EFrontSide | ESpatiallyVarying);

        m_usesRayDifferentials = false;

        BSDF::configure();
    }

    void components_transfer_factors(Vector3 wi,
                                     const Spectrum* etas,
                                     const Spectrum* kappas,
                                     const Float*    alphas,
                                     component_factors_2* ops) const {

        // Current layer attributes
        Spectrum etas_ij;

        // Layer iterations
        for (int i = 0; i < m_layer_count; ++i) {

            // IoR
            etas_ij = etas[i+1] / etas[i];

            if (kappas[i+1].isZero()) {

                // Dielectric interface
                dielectric_transfer_factors(wi, etas_ij.average(), alphas[i+1], m_FGD, ops[i]);

                // Propagation direction update
                wi = -ops[i].t.mean;
            }
            else {

                // Conductor substrate
                conductor_transfer_factors(wi, etas_ij, kappas[i+1] / etas[i], alphas[i+1], m_FGD, ops[i]);
            }
        }
    }
    void outgoing_lobes(const Vector3& wi,
                        const Spectrum* etas,
                        const Spectrum* kappas,
                        const Float* alphas,
                        hg* lobes) const {

        // Components transfer factors
        component_factors_2 ops[TM_LAYER_COUNT_MAX];

        // Current component attributes
        Float eta_ij, eta_ji;
        Spectrum e_r_i;
        Float e_r_i_avg;

        // Cumulated components attributes
        Spectrum e_r_0h(0.f), e_r_0i(0.f);
        Float g_r_0h = 0.f, g_r_0i;

        // First-order terms
        Float g_T_0i = 1.f, g_T_0j = 1.f, g_T_0j_R = 1.f, g_T_0j_RT = 1.f;

        // TIR
        Spectrum tir_norm;

        // Transfer matrices
        transfer_matrix_2s etm_0i = transfer_matrix_2s::identity();
        transfer_matrix_21 gtm_0i = transfer_matrix_21::identity();

        ////////////////////////////////////////////////////////////////////////////////
        //
        // For readibility purpose, we first extract the transfer factors of each
        // component before the actual transfer matrix calculus loop
        //
        ////////////////////////////////////////////////////////////////////////////////

        components_transfer_factors(wi, etas, kappas, alphas, ops);

        ////////////////////////////////////////////////////////////////////////////////
        //
        // Components iterations
        //
        //  1) Compute first-order dielectric transmission factors and account for TIR
        //  2) Compute transfer matrices
        //  3) Compute outgoing lobe statistics based upon the transfer matrices
        //
        ////////////////////////////////////////////////////////////////////////////////

        for (int i = 0; i < m_layer_count; ++i) {

            if (ops[i].type == EDielectricInterface) {

                // Scalar IoR
                eta_ij = (etas[i+1] / etas[i]).average();
                eta_ji = 1.f / eta_ij;

                // First-order terms
                g_T_0j      = hg_refract(g_T_0i, eta_ji) * ops[i].t.g;
                g_T_0j_R    = g_T_0j * ops[i+1].r.g;
                g_T_0j_RT   = hg_refract(g_T_0j_R, eta_ij) * ops[i].tp.g;

                // Downward transmission
                ops[i].t.g = g_T_0i != 0.f ? g_T_0j / g_T_0i : 0.f;

                // Upward transmission
                ops[i].tp.g = g_T_0j_R != 0.f ? g_T_0j_RT / g_T_0j_R : 0.f;

                if (eta_ij < 1.f) {

                    // Downward TIR
                    tir_norm = m_TIR.range_get_interpolate(std::abs(ops[i].r.mean.z), hg_to_ggx(g_T_0i), eta_ij) * ops[i].t.norm;

                    ops[i].r.norm += tir_norm;
                    ops[i].t.norm -= tir_norm;
                }
                else {

                    // Upward TIR
                    tir_norm = m_TIR.range_get_interpolate(std::abs(ops[i].t.mean.z), hg_to_ggx(g_T_0j_R), eta_ji) * ops[i].tp.norm;

                    ops[i].rp.norm += tir_norm;
                    ops[i].tp.norm -= tir_norm;
                }

                ////////////////////////////////////////////////////////////////
                // Transfer matrices evaluation
                ////////////////////////////////////////////////////////////////
                
                etm_0i *= energy_matrix(ops[i]);
                gtm_0i *= asymmetry_matrix(ops[i]);

                e_r_0i = etm_0i.r();
                g_r_0i = gtm_0i.r();
            }
            else {

                ////////////////////////////////////////////////////////////////
                // Transfer matrices evaluation
                ////////////////////////////////////////////////////////////////

                e_r_0i = etm_0i.r(ops[i].r.norm);
                g_r_0i = gtm_0i.r(ops[i].r.norm.average() * ops[i].r.g);
            }

            ////////////////////////////////////////////////////////////////////
            // Reflected lobe
            ////////////////////////////////////////////////////////////////////

            // Energy
            e_r_i       = e_r_0i - e_r_0h;
            e_r_i_avg   = e_r_i.average();

            // Lobe attributes
            lobes[i].norm   = e_r_i;
            lobes[i].g      = e_r_i_avg > 0.f ? std::min((g_r_0i - g_r_0h) / e_r_i_avg, 1.f) : 0.f;

            // Top layers attributes update
            e_r_0h = e_r_0i;
            g_r_0h = g_r_0i;

            // First-order terms update
            g_T_0i = g_T_0j;
        }
    }

    inline void evalMaps(const BSDFSamplingRecord &bRec,
                         Spectrum* etas, Spectrum* kappas, Float* alphas) const {

        // External medium properties
        etas[0] = m_tex_etas[0]->eval(bRec.its);

        // Layers properties
        for(int i = 1; i <= m_layer_count; ++i) {

            etas[i]   = m_tex_etas[i]->eval(bRec.its);
            kappas[i] = m_tex_kappas[i]->eval(bRec.its);
            alphas[i] = m_tex_alphas[i]->eval(bRec.its).average();
        }
    }

    Spectrum eval(const BSDFSamplingRecord &bRec, EMeasure measure) const {

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        Spectrum    kappas[TM_LAYER_COUNT_MAX];
        Float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, kappas, alphas);

        return this->eval(bRec, measure, etas, kappas, alphas);
    }
    Spectrum eval(const BSDFSamplingRecord &bRec, EMeasure measure,
                  const Spectrum* etas, const Spectrum* kappas, const Float* alphas) const {

        if (measure != ESolidAngle || bRec.wi.z <= 0 || bRec.wo.z <= 0)
            return Spectrum(0.0f);

        // Half-vector
        const Vector3 H = normalize(bRec.wi + bRec.wo);

        ////////////////////////////////////////////////////////////////////////
        // Lobes
        ////////////////////////////////////////////////////////////////////////

        hg lobes[TM_LAYER_COUNT_MAX];

        outgoing_lobes(bRec.wi, etas, kappas, alphas, lobes);

        ////////////////////////////////////////////////////////////////////////
        // Throughput
        ////////////////////////////////////////////////////////////////////////

        // [Bati2019] Top reflection correction
        const MicrofacetDistribution ndf_0(MicrofacetDistribution::EGGX, alphas[1], true);

        const Float G2_0    = ndf_0.G(bRec.wi, bRec.wo, H);
        const Float D_0     = ndf_0.eval(H);

        Spectrum F_0;
        const Spectrum etas_01 = etas[1] / etas[0];
        if (kappas[1].isZero())
            F_0 = Spectrum(fresnelDielectricExt(dot(bRec.wi, H), etas_01.average()));
        else
            F_0 = fresnelConductorExact(dot(bRec.wi, H), etas_01, kappas[1] / etas[0]);

        Spectrum throughput = F_0 * G2_0 * D_0 / (4.f * bRec.wi.z);

        // Eval and sum internal lobes contributions
        for (int i = 1; i < m_layer_count; ++i) {

            if (lobes[i].norm.isZero())
                continue;

            // GGX equivalent normal distribution
            const Float a = hg_to_ggx(lobes[i].g);
            const MicrofacetDistribution ndf(MicrofacetDistribution::EGGX, a, true);

            const Float G2  = ndf.G(bRec.wi, bRec.wo, H);
            const Float D   = ndf.eval(H);

            // Ideal BRDF eval
            const Float f = G2 * D / (4.f * bRec.wi.z);

            throughput += lobes[i].norm * f;
        }

        Assert(!throughput.isNaN());

        return throughput;
    }

    Float pdf(const BSDFSamplingRecord& bRec, EMeasure measure) const {

        if (measure != ESolidAngle || bRec.wi.z <= 0 || bRec.wo.z <= 0)
            return 0.f;

        // Half-vector
        const Vector3 H = normalize(bRec.wi + bRec.wo);

        ////////////////////////////////////////////////////////////////////////
        // Lobes
        ////////////////////////////////////////////////////////////////////////

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        Spectrum    kappas[TM_LAYER_COUNT_MAX];
        Float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, kappas, alphas);

        hg lobes[TM_LAYER_COUNT_MAX];

        outgoing_lobes(bRec.wi, etas, kappas, alphas, lobes);

        ////////////////////////////////////////////////////////////////////////
        // PDF
        ////////////////////////////////////////////////////////////////////////

        Float w_sum = 0.f;
        Float wpdf_sum = 0.f;
        for (int i = 0; i < m_layer_count; ++i) {

            if (lobes[i].norm.isZero())
                continue;

            // GGX equivalent normal distribution
            const Float a = hg_to_ggx(lobes[i].g);
            const MicrofacetDistribution ndf(MicrofacetDistribution::EGGX, a, true);

            const Float G1  = ndf.smithG1(bRec.wi, H);
            const Float D   = ndf.eval(H);

            const Float norm = lobes[i].norm.average();

            w_sum       += norm;
            wpdf_sum    += norm * G1 * D / (4.0f * bRec.wi.z);
        }

        Assert(!(std::isnan(wpdf_sum) || std::isinf(wpdf_sum)));

        return w_sum > 0.f ? wpdf_sum / w_sum : 0.f;
    }

    Spectrum sample(BSDFSamplingRecord& bRec, const Point2& sample) const {

        Float dummy;
        return this->sample(bRec, dummy, sample);
    }
    Spectrum sample(BSDFSamplingRecord& bRec, Float& pdf, const Point2& sample) const {

        if (bRec.wi.z < 0)
            return Spectrum(0.f);

        ////////////////////////////////////////////////////////////////////////
        // Lobes
        ////////////////////////////////////////////////////////////////////////

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        Spectrum    kappas[TM_LAYER_COUNT_MAX];
        Float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, kappas, alphas);

        hg lobes[TM_LAYER_COUNT_MAX];

        outgoing_lobes(bRec.wi, etas, kappas, alphas, lobes);

        //////////////////////////////////////////////////////////////////////
        // Random lobe selection
        //////////////////////////////////////////////////////////////////////

        // Lobes probabilities
        Float w[TM_LAYER_COUNT_MAX];
        Float w_sum = 0.f;
        for(int i = 0; i < m_layer_count; ++i) {

            w[i] = lobes[i].norm.average();
            w_sum += w[i];
        }

        // Lobe selection
        Float sel_w = bRec.sampler->next1D() * w_sum - w[0];
        int   sel_i = 0;
        for(sel_i = 0; sel_w > 0.f && sel_i < m_layer_count; ++sel_i)
            sel_w -= w[sel_i + 1];

        //////////////////////////////////////////////////////////////////////
        // Sampling
        //////////////////////////////////////////////////////////////////////

        // Selected lobe equivalent GGX normal distribution
        const Float sel_a = hg_to_ggx(lobes[sel_i].g);
        const MicrofacetDistribution sel_ndf(MicrofacetDistribution::EGGX, sel_a, true);

        // Selected lobe normal sampling
        const Normal H = sel_ndf.sample(bRec.wi, sample, pdf);

        // Sampled direction
        bRec.wo = reflect(bRec.wi, H);
        bRec.eta = 1.f;
        bRec.sampledComponent = 0;
        bRec.sampledType = EGlossyReflection;

        if(bRec.wo.z <= 0.f || pdf <= 0.f)
            return Spectrum(0.0f);

        //////////////////////////////////////////////////////////////////////
        // PDF
        //////////////////////////////////////////////////////////////////////

        pdf = 0.f;
        for(int i = 0; i < m_layer_count; ++i) {

            if (w[i] > 0.f) {

                // GGX equivalent normal distribution
                const Float a = hg_to_ggx(lobes[i].g);
                const MicrofacetDistribution ndf(MicrofacetDistribution::EGGX, a, true);

                const Float G1  = ndf.smithG1(bRec.wi, H);
                const Float D   = ndf.eval(H);

                pdf += w[i] * G1 * D / (4.0f * bRec.wi.z);
            }
        }
        pdf /= w_sum;

        //////////////////////////////////////////////////////////////////////
        // Throughput
        //////////////////////////////////////////////////////////////////////

        Spectrum throughput = this->eval(bRec, ESolidAngle, etas, kappas, alphas);

        Assert(!throughput.isNaN());

        return pdf > 0.f ? throughput / pdf : Spectrum(0.0f);
    }

    MTS_DECLARE_CLASS()
};

MTS_IMPLEMENT_CLASS_S(TM2, false, BSDF)
MTS_EXPORT_PLUGIN(TM2, "TM2");
MTS_NAMESPACE_END

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Contact— JavaScript license information— Web API

back to top