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_dielectric.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:4a31376b5417c63417e639687931b5206499f047
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_dielectric.cpp
#include "tm.h"

MTS_NAMESPACE_BEGIN

class TM2_dielectric : public BSDF {
private:

    // Layers parameters
    int m_layer_count;
    int m_lobe_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_dielectric(const Properties& props): BSDF(props) {

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

        m_lobe_count = m_layer_count + 1;

        // 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_dielectric(Stream* stream, InstanceManager* manager): BSDF(stream, manager) {

        configure();
    }

    void configure() {

        m_components.clear();
        m_components.push_back(EGlossyReflection | EFrontSide | EBackSide | ESpatiallyVarying);
        m_components.push_back(EGlossyTransmission | EFrontSide | EBackSide | ESpatiallyVarying | ENonSymmetric);

        m_usesRayDifferentials = false;

        BSDF::configure();
    }

    void components_transfer_factors(Vector3 wi,
                                     const Spectrum* etas,
                                     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) {

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

            // Propagation direction update
            wi = -ops[i].t.mean;
        }
    }
    void outgoing_lobes(const Vector3& wi,
                        const Spectrum* etas,
                        const float* alphas,
                        hg* lobes,
                        Vector3* lobes_wi) const {

        // Components transfer factors
        component_factors_2 ops[TM_LAYER_COUNT_MAX];

        // Current interface attributes
        float eta_ij, eta_ji;
        Spectrum e_r_i;
        float e_r_i_avg;

        // Cumulated interfaces attributes
        Spectrum e_r_0h(0.f), e_r_0i, e_t_0i;
        float e_t_0i_avg;
        float g_r_0h = 0.f, g_r_0i, g_t_0i;

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

        // 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, 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) {

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

            ////////////////////////////////////////////////////////////////////
            // Transmission correction
            ////////////////////////////////////////////////////////////////////

            // First-order terms
            g_T_0j      = hg_refract(g_T_0i, eta_ji) * ops[i].t.g;
            g_T_0j_R    = i < (m_layer_count - 1) ? g_T_0j * ops[i+1].r.g : 1.f;
            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]);

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

            // Norm
            e_r_0i      = etm_0i.r();
            e_r_i       = e_r_0i - e_r_0h;
            e_r_i_avg   = e_r_i.average();

            // Asymmetry parameter
            g_r_0i = gtm_0i.r();

            // Reflected lobe
            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;
            lobes_wi[i] = wi;

            // 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;
        }

        ////////////////////////////////////////////////////////////////////////
        // Transmitted lobe
        ////////////////////////////////////////////////////////////////////////

        // Norm
        e_t_0i      = etm_0i.t();
        e_t_0i_avg  = e_t_0i.average();

        // Asymmetry parameter
        g_t_0i = gtm_0i.t();

        // Transmitted lobe
        lobes[m_layer_count].norm   = e_t_0i;
        lobes[m_layer_count].g      = e_t_0i_avg > 0.f ? std::min(g_t_0i / e_t_0i_avg, 1.f) : 0.f;
        lobes_wi[m_layer_count] = reflectZ(ops[m_layer_count - 1].t.mean);
    }

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

        const bool rev = bRec.wi.z < 0.f;

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

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

            etas[i]   = m_tex_etas[rev ? m_layer_count - i : i]->eval(bRec.its);
            alphas[i] = m_tex_alphas[rev ? m_layer_count - i + 1 : i]->eval(bRec.its).average();
        }
    }

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

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, alphas);

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

        if (measure != ESolidAngle || Frame::cosTheta(bRec.wi) == 0)
            return Spectrum(0.0f);

        // Interaction type
        bool reflect = Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) > 0;

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

        hg      lobes[TM_LAYER_COUNT_MAX];
        Vector3 lobes_wi[TM_LAYER_COUNT_MAX];

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

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

        // Radiance transmission scaling factor
        const float factor = reflect ? 1.f : (etas[0] / etas[m_layer_count]).average();

        // Eval and sum lobe contributions according to the interaction type
        Spectrum throughput = Spectrum(0.f);
        for (int i = 0; i < m_lobe_count; ++i) {

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

            if (lobes_wi[i].z * bRec.wo.z <= 0.f)
                continue;

            // Eval directions (upper hemisphere)
            Vector3 wi = lobes_wi[i];
            Vector3 wo = bRec.wo;

            wi.z = std::abs(wi.z);
            wo.z = std::abs(wo.z);

            // Half-vector (upper hemisphere)
            const Vector3 H = normalize(wi + wo);

            // 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(wi, wo, H);
            const float D = ndf.eval(H);

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

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

        Assert(!throughput.isNaN());

        return throughput;
    }

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

        if (measure != ESolidAngle)
            return 0.f;

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

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, alphas);

        hg      lobes[TM_LAYER_COUNT_MAX];
        Vector3 lobes_wi[TM_LAYER_COUNT_MAX];

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

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

        float w_sum = 0.f;
        float wpdf_sum = 0.f;
        for (int i = 0; i < m_lobe_count; ++i) {

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

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

            w_sum += norm;

            if (lobes_wi[i].z * bRec.wo.z <= 0.f)
                continue;

            // Reflection eval directions (upper hemisphere)
            Vector3 wi = lobes_wi[i];
            Vector3 wo = bRec.wo;

            wi.z = std::abs(wi.z);
            wo.z = std::abs(wo.z);

            // Half-vector (upper hemisphere)
            const Vector3 H = normalize(wi + wo);

            // 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(wi, H);
            const float D   = ndf.eval(H);

            wpdf_sum += norm * G1 * D / (4.0f * 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 {

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

        // Get layers properties
        Spectrum    etas[TM_LAYER_COUNT_MAX];
        float       alphas[TM_LAYER_COUNT_MAX];

        evalMaps(bRec, etas, alphas);

        hg      lobes[TM_LAYER_COUNT_MAX];
        Vector3 lobes_wi[TM_LAYER_COUNT_MAX];

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

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

        // Lobes probabilities
        float w[TM_LAYER_COUNT_MAX];
        float w_sum = 0.f;
        for(int i = 0; i < m_lobe_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_lobe_count; ++sel_i)
            sel_w -= w[sel_i + 1];

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

        // Interaction type
        const bool reflection = bRec.wi.z * lobes_wi[sel_i].z > 0.f;

        // 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 reflection eval direction (upper hemisphere)
        Vector3 sel_wi = lobes_wi[sel_i];
        sel_wi.z = std::abs(sel_wi.z);

        // Selected lobe normal sampling (upper hemisphere)
        const Normal H = sel_ndf.sample(sel_wi, sample, pdf);

        // Sampled direction
        Vector3 sel_wo = reflect(sel_wi, H);
        sel_wo.z *= math::signum(bRec.wi.z) * (reflection ? 1.f : -1.f);

        // Sampling record
        bRec.wo = sel_wo;
        bRec.eta = etas[reflection ? 0 : m_layer_count].average();
        bRec.sampledComponent = reflection ? 0 : 1;
        bRec.sampledType = reflection ? EGlossyReflection : EGlossyTransmission;

        if(pdf <= 0.f)
            return Spectrum(0.0f);

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

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

            if (w[i] == 0.f)
                continue;

            if (lobes_wi[i].z * bRec.wo.z <= 0.f)
                continue;

            // Reflection eval directions (upper hemisphere)
            Vector3 wi = lobes_wi[i];
            Vector3 wo = bRec.wo;

            wi.z = std::abs(wi.z);
            wo.z = std::abs(wo.z);

            // Half-vector (upper hemisphere)
            const Vector3 H = normalize(wi + wo);

            // 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(wi, H);
            const float D = ndf.eval(H);

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

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

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

        Assert(!throughput.isNaN());

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

    MTS_DECLARE_CLASS()
};

MTS_IMPLEMENT_CLASS_S(TM2_dielectric, false, BSDF)
MTS_EXPORT_PLUGIN(TM2_dielectric, "TM2_dielectric");
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