@@ -201,8 +201,8 @@ bool CMitsubaLoader::isALoadableFileFormat(system::IFile* _file, const system::l
201201
202202
203203// TODO: make configurable
204- constexpr bool PrintMaterialDot3 = false ;
205- system::path DebugDir (" /tmp " );
204+ constexpr bool PrintMaterialDot3 = true ;
205+ system::path DebugDir (" D: \\ work \\ Nabla-master \\ examples_tests \\ 15_MitsubaLoader \\ bin " );
206206//
207207void SContext::writeDot3File (system::ISystem* system, const system::path& filepath, frontend_ir_t ::SDotPrinter& printer)
208208{
@@ -497,6 +497,9 @@ void getParameter(const std::span<parameter_t,3> out, const CElementTexture::Spe
497497 else
498498 switch (src.value .type )
499499 {
500+ case SPropertyElementData::Type::FLOAT:
501+ getParameter ({out.data (),out.size ()},src.value .fvalue );
502+ break ;
500503 case SPropertyElementData::Type::SRGB: [[fallthrough]]; // already linearized when parsed!
501504 case SPropertyElementData::Type::RGB:
502505 getParameter<3 >(out,src.value .vvalue .xyz );
@@ -525,11 +528,23 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
525528 // this is also our top coating layer
526529 auto rootH = frontPool.emplace <frontend_ir_t ::CLayer>();
527530
528- auto createMistubaLeaf = [&]()->frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode>
531+ struct SLeaf
532+ {
533+ frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode> top = {};
534+ frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode> trans = {};
535+ };
536+ auto createMistubaLeaf = [&](const CElementBSDF* _bsdf/* TODO: debug source information*/ )->SLeaf
529537 {
530- switch (bsdf->type )
538+ using ndf_e = frontend_ir_t ::CCookTorrance::NDF;
539+ constexpr ndf_e ndfMap[4 ] = {
540+ ndf_e::Beckmann,
541+ ndf_e::GGX,
542+ ndf_e::Beckmann, // Phong can be mapped to Beckmann
543+ ndf_e::Beckmann // Ahskhmin is Ani Beckmann last I remember
544+ };
545+ switch (_bsdf->type )
531546 {
532- case CElementBSDF::DIFFUSE:
547+ case CElementBSDF::DIFFUSE: [[fallthrough]];
533548 case CElementBSDF::ROUGHDIFFUSE:
534549 {
535550 const auto roughDiffuseH = frontPool.emplace <frontend_ir_t ::CMul>();
@@ -539,10 +554,10 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
539554 const auto orenNayarH = frontPool.emplace <frontend_ir_t ::COrenNayar>();
540555 auto * orenNayar = frontPool.deref (orenNayarH);
541556 auto roughness = orenNayar->ndParams .getRougness ();
542- if (bsdf ->type ==CElementBSDF::ROUGHDIFFUSE)
557+ if (_bsdf ->type ==CElementBSDF::ROUGHDIFFUSE)
543558 {
544559 // we only support isotropic Oren-Nayar
545- getParameter (roughness,bsdf ->diffuse .alpha );
560+ getParameter (roughness,_bsdf ->diffuse .alpha );
546561 }
547562 else
548563 roughness[0 ].scale = roughness[1 ].scale = 0 .f ;
@@ -551,13 +566,120 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
551566 {
552567 spectral_var_t ::SCreationParams<3 > params = {};
553568 params.getSemantics () = spectral_var_t ::Semantics::Fixed3_SRGB;
554- getParameter (params.knots .params ,bsdf ->diffuse .reflectance );
555- const auto albedoH = frontPool.emplace <frontend_ir_t ::CSpectralVariable >(std::move (params));
569+ getParameter (params.knots .params ,_bsdf ->diffuse .reflectance );
570+ const auto albedoH = frontPool.emplace <spectral_var_t >(std::move (params));
556571 frontPool.deref (albedoH)->debugInfo = commonDebugNames[uint16_t (ECommonDebug::Albedo)]._const_cast ();
557572 mul->rhs = albedoH;
558573 }
559574 }
560- return roughDiffuseH;
575+ return {.top =roughDiffuseH};
576+ }
577+ case CElementBSDF::DIELECTRIC: [[fallthrough]];
578+ case CElementBSDF::THINDIELECTRIC: [[fallthrough]];
579+ case CElementBSDF::ROUGHDIELECTRIC: [[fallthrough]];
580+ case CElementBSDF::CONDUCTOR: [[fallthrough]];
581+ case CElementBSDF::ROUGHCONDUCTOR:
582+ {
583+ const auto handle = frontPool.emplace <frontend_ir_t ::CMul>();
584+ frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode> trans = {};
585+ {
586+ const bool isConductor = _bsdf->type ==CElementBSDF::CONDUCTOR || _bsdf->type ==CElementBSDF::ROUGHCONDUCTOR;
587+ // beautiful thing we can reuse the same nodes for a transmission function without touching Etas or anything!
588+ if (!isConductor)
589+ trans = handle;
590+ //
591+ auto * mul = frontPool.deref (handle);
592+ const auto ctH = frontPool.emplace <frontend_ir_t ::CCookTorrance>();
593+ auto * const ct = frontPool.deref (ctH);
594+ {
595+ auto roughness = ct->ndParams .getRougness ();
596+ if (_bsdf->type ==CElementBSDF::ROUGHCONDUCTOR)
597+ {
598+ const CElementBSDF::RoughSpecularBase* rough = &_bsdf->dielectric ;
599+ if (isConductor)
600+ rough = &_bsdf->conductor ;
601+ // ct->orientedRealEta gets set in the fresnel part
602+ ct->ndf = ndfMap[rough->distribution ];
603+ getParameter (roughness,rough->alphaU );
604+ if (rough->alphaV .texture || !hlsl::isnan (rough->alphaV .value ))
605+ getParameter (roughness,rough->alphaU );
606+ else
607+ roughness[1 ] = roughness[0 ];
608+ }
609+ else
610+ roughness[0 ].scale = roughness[1 ].scale = 0 .f ;
611+ mul->lhs = ctH;
612+ }
613+ // Now the fresnels
614+ // do the artificial Mitsuba factor
615+ {
616+ const auto reflectanceMulH = frontPool.emplace <frontend_ir_t ::CMul>();
617+ {
618+ auto * const reflectanceMul = frontPool.deref (reflectanceMulH);
619+ {
620+ const auto fresnelH = frontPool.emplace <frontend_ir_t ::CFresnel>();
621+ auto * const fresnel = frontPool.deref (fresnelH);
622+ if (isConductor)
623+ {
624+ const float extEta = _bsdf->conductor .extEta ;
625+ {
626+ spectral_var_t ::SCreationParams<3 > params = {};
627+ params.getSemantics () = spectral_var_t ::Semantics::Fixed3_SRGB;
628+ const hlsl::float32_t3 eta = _bsdf->conductor .eta .vvalue .xyz ;
629+ getParameter<3 >(params.knots .params ,eta/extEta);
630+ fresnel->orientedRealEta = frontPool.emplace <spectral_var_t >(std::move (params));
631+ }
632+ {
633+ spectral_var_t ::SCreationParams<3 > params = {};
634+ params.getSemantics () = spectral_var_t ::Semantics::Fixed3_SRGB;
635+ const hlsl::float32_t3 k = _bsdf->conductor .k .vvalue .xyz ;
636+ getParameter<3 >(params.knots .params ,k/extEta);
637+ fresnel->orientedImagEta = frontPool.emplace <spectral_var_t >(std::move (params));
638+ }
639+ }
640+ else
641+ {
642+ spectral_var_t ::SCreationParams<1 > params = {};
643+ params.knots .params [0 ].scale = _bsdf->dielectric .intIOR /_bsdf->dielectric .extIOR ;
644+ ct->orientedRealEta = fresnel->orientedRealEta = frontPool.emplace <spectral_var_t >(std::move (params));
645+ }
646+ reflectanceMul->lhs = fresnelH;
647+ // make the trans node refraction-less for thin dielectric and apply thin scattering correction to the transmissive fresnel
648+ if (_bsdf->type ==CElementBSDF::THINDIELECTRIC)
649+ {
650+ const auto btdfH = frontPool.emplace <frontend_ir_t ::CMul>();
651+ {
652+ auto * mul = frontPool.deref (btdfH);
653+ // apply energy conserving correction
654+ const auto thinInfiniteScatterH = frontPool.emplace <frontend_ir_t ::CThinInfiniteScatterCorrection>();
655+ {
656+ auto * thinInfiniteScatter = frontPool.deref (thinInfiniteScatterH);
657+ thinInfiniteScatter->reflectanceTop = fresnelH;
658+ thinInfiniteScatter->reflectanceBottom = fresnelH;
659+ // TODO: extinction
660+ }
661+ mul->lhs = frontPool.emplace <frontend_ir_t ::CDeltaTransmission>(); // TODO: commonalize
662+ mul->rhs = thinInfiniteScatterH;
663+ }
664+ trans = btdfH;
665+ }
666+ }
667+ {
668+ spectral_var_t ::SCreationParams<3 > params = {};
669+ params.getSemantics () = spectral_var_t ::Semantics::Fixed3_SRGB;
670+ if (isConductor)
671+ getParameter (params.knots .params ,_bsdf->conductor .specularReflectance );
672+ else // we'll do the specularTransmittance on the btdf stack element when cloning
673+ getParameter (params.knots .params ,_bsdf->dielectric .specularReflectance );
674+ const auto artificialReflectanceH = frontPool.emplace <spectral_var_t >(std::move (params));
675+ frontPool.deref (artificialReflectanceH)->debugInfo = commonDebugNames[uint16_t (ECommonDebug::MitsubaExtraFactor)]._const_cast ();
676+ reflectanceMul->rhs = artificialReflectanceH;
677+ }
678+ }
679+ mul->rhs = reflectanceMulH;
680+ }
681+ }
682+ return {.top =handle,.trans =trans};
561683 }
562684 default :
563685 assert (false ); // we shouldn't get this case here
@@ -568,7 +690,24 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
568690 // Post-order Depth First Traversal (create children first, then create parent)
569691 if (bsdf->isMeta ()) // TODO: temporary
570692 return {};
571- frontPool.deref (rootH)->brdfTop = createMistubaLeaf ();
693+ auto * const layer = frontPool.deref (rootH);
694+ {
695+ const SLeaf leaf = createMistubaLeaf (bsdf);
696+ layer->brdfTop = leaf.top ;
697+ layer->btdf = leaf.trans ;
698+ }
699+ // handle BTDF and bottom BRDF layer
700+ switch (bsdf->type )
701+ {
702+ case CElementBSDF::DIELECTRIC: [[fallthrough]];
703+ case CElementBSDF::THINDIELECTRIC: [[fallthrough]];
704+ case CElementBSDF::ROUGHDIELECTRIC:
705+ // material compiler is designed so that we don't need to reciprocate the BRDFs as we go through layers as long as observer is still on the same side
706+ layer->brdfBottom = layer->brdfTop ;
707+ break ;
708+ default :
709+ break ;
710+ }
572711#if 0
573712 core::stack<const CElementBSDF*> stack;
574713 stack.push(bsdf);
@@ -887,6 +1026,7 @@ SContext::SContext(
8871026 {
8881027#define ADD_DEBUG_NODE (NAME ) commonDebugNames[uint16_t (ECommonDebug::NAME)] = frontPool.emplace<frontend_ir_t ::CDebugInfo>(#NAME)
8891028 ADD_DEBUG_NODE (Albedo);
1029+ ADD_DEBUG_NODE (MitsubaExtraFactor);
8901030#undef ADD_DEBUG_NODE
8911031 }
8921032 }
0 commit comments