@@ -371,6 +371,7 @@ auto SContext::getMaterial(
371371 {
372372 // only front-face on top layer get changed, Mistuba XML only allows for unobscured/uncoated emission
373373 {
374+ // TODO replace with utility
374375 auto combinerH = frontPool.emplace <frontend_ir_t ::CAdd>();
375376 auto * const combiner = frontPool.deref (combinerH);
376377 combiner->lhs = foundEmitter->second ._const_cast ();
@@ -624,22 +625,43 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
624625
625626 auto createFactorNode = [&](const CElementTexture::SpectrumOrTexture& factor, const ECommonDebug debug)->auto
626627 {
627- const auto mulH = frontPool.emplace <frontend_ir_t ::CMul>();
628- auto * mul = frontPool.deref (mulH);
629628 spectral_var_t ::SCreationParams<3 > params = {};
630629 params.knots .uvTransform = getParameters (params.knots .params ,factor);
631630 params.getSemantics () = spectral_var_t ::Semantics::Fixed3_SRGB;
632631 const auto factorH = frontPool.emplace <spectral_var_t >(std::move (params));
633632 frontPool.deref (factorH)->debugInfo = commonDebugNames[uint16_t (debug)]._const_cast ();
634- mul->rhs = factorH;
633+ return factorH;
634+ };
635+ // TODO: Move this lambda to CFrontendIR for everyone to use
636+ using expr_t = frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode>;
637+ auto mul = [&](const expr_t original, const expr_t factor)->frontend_ir_t ::typed_pointer_type<frontend_ir_t ::CMul>
638+ {
639+ // if there was no original, attenuating a black colour is useless
640+ if (!original)
641+ return {};
642+ const auto mulH = frontPool.emplace <frontend_ir_t ::CMul>();
643+ auto * const mul = frontPool.deref (mulH);
644+ mul->lhs = original;
645+ mul->rhs = factor;
635646 return mulH;
636647 };
648+ auto add = [&](const expr_t lhs, const expr_t rhs)->expr_t
649+ {
650+ if (!lhs)
651+ return rhs;
652+ if (!rhs)
653+ return lhs;
654+ const auto addH = frontPool.emplace <frontend_ir_t ::CAdd>();
655+ auto * const add = frontPool.deref (addH);
656+ add->lhs = lhs;
657+ add->rhs = rhs;
658+ return addH;
659+ };
660+ // end TODO
637661 auto createCookTorrance = [&](const CElementBSDF::RoughSpecularBase* base, const frontend_ir_t ::typed_pointer_type<frontend_ir_t ::CFresnel> fresnelH, const CElementTexture::SpectrumOrTexture& specularReflectance)->auto
638662 {
639- const auto handle = createFactorNode (specularReflectance,ECommonDebug::MitsubaExtraFactor);
640- // rhs already filled, waiting for contributor in lhs subtree
641663 const auto mulH = frontPool.emplace <frontend_ir_t ::CMul>();
642- frontPool. deref (handle)-> lhs = mulH ;
664+ const auto factorH = createFactorNode (specularReflectance,ECommonDebug::MitsubaExtraFactor) ;
643665 {
644666 auto * mul = frontPool.deref (mulH);
645667 const auto ctH = frontPool.emplace <frontend_ir_t ::CCookTorrance>();
@@ -675,13 +697,13 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
675697 mul->lhs = ctH;
676698 mul->rhs = fresnelH;
677699 }
678- return handle ;
700+ return mul (mulH,factorH) ;
679701 };
680702 auto createOrenNayar = [&](const CElementTexture::SpectrumOrTexture& albedo, const CElementTexture::FloatOrTexture& alphaU, const CElementTexture::FloatOrTexture& alphaV)->auto
681703 {
682- const auto mulH = createFactorNode (albedo,ECommonDebug::Albedo);
704+ const auto orenNayarH = frontPool.emplace <frontend_ir_t ::COrenNayar>();
705+ const auto factorH = createFactorNode (albedo,ECommonDebug::Albedo);
683706 {
684- const auto orenNayarH = frontPool.emplace <frontend_ir_t ::COrenNayar>();
685707 auto * orenNayar = frontPool.deref (orenNayarH);
686708 // TODO: factor this out between Oren-Nayar and Cook Torrance
687709 auto roughness = orenNayar->ndParams .getRougness ();
@@ -691,16 +713,16 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
691713 // TODO: check if UV transform is the same and warn if not
692714 getParameters ({roughness.data ()+1 ,1 },alphaV);
693715 }
694- frontPool.deref (mulH)->lhs = orenNayarH;
695716 }
696- return mulH ;
717+ return mul (orenNayarH,factorH) ;
697718 };
698719
720+ using bxdf_t = frontend_ir_t ::typed_pointer_type<frontend_ir_t ::IExprNode>;
699721 // the layer returned will never have a bottom BRDF
700722 auto createMistubaLeaf = [&](const CElementBSDF* _bsdf/* TODO: debug source information*/ )->frontend_ir_t ::typed_pointer_type<frontend_ir_t ::CLayer>
701723 {
702724 auto retval = frontPool.emplace <frontend_ir_t ::CLayer>();
703- auto * const leaf = frontPool.deref (retval);
725+ auto * leaf = frontPool.deref (retval);
704726 switch (_bsdf->type )
705727 {
706728 case CElementBSDF::DIFFUSE: [[fallthrough]];
@@ -782,10 +804,10 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
782804 if (!isConductor)
783805 {
784806 // want a specularTransmittance instead of SpecularReflectance factor
785- const auto btdfH = createFactorNode (_bsdf->dielectric .specularTransmittance ,ECommonDebug::MitsubaExtraFactor);
807+ const auto factorH = createFactorNode (_bsdf->dielectric .specularTransmittance ,ECommonDebug::MitsubaExtraFactor);
808+ bxdf_t btdfH;
786809 {
787810 const auto * const brdf = frontPool.deref (brdfH);
788- auto * const btdf = frontPool.deref (btdfH);
789811 // make the trans node refraction-less for thin dielectric and apply thin scattering correction to the transmissive fresnel
790812 if (_bsdf->type ==CElementBSDF::THINDIELECTRIC)
791813 {
@@ -804,12 +826,12 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
804826 mul->rhs = thinInfiniteScatterH;
805827 }
806828 // we're rethreading the fresnel here
807- btdf-> lhs = correctedTransmissionH;
829+ btdfH = correctedTransmissionH;
808830 }
809- else // beautiful thing we can reuse the same nodes for a transmission function without touching Etas or anything!
810- btdf-> lhs = brdf->lhs ;
831+ else // beautiful thing we can reuse the same BxDF nodes for a transmission function without touching Etas or anything!
832+ btdfH = brdf->lhs ;
811833 }
812- leaf->btdf = btdfH;
834+ leaf->btdf = mul ( btdfH,factorH) ;
813835 }
814836 break ;
815837 }
@@ -821,11 +843,10 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
821843 leaf->brdfTop = dielectricH;
822844 const auto transH = frontPool.emplace <frontend_ir_t ::CMul>();
823845 {
824- auto * const mul = frontPool.deref (transH);
825- mul->lhs = deltaTransmission._const_cast ();
826- const auto transmittanceH = createFactorNode (_bsdf->plastic .specularTransmittance ,ECommonDebug::MitsubaExtraFactor);
827- frontPool.deref (transmittanceH)->lhs = fresnelH;
828- mul->rhs = transmittanceH;
846+ auto * const trans = frontPool.deref (transH);
847+ trans->lhs = deltaTransmission._const_cast ();
848+ const auto factorH = createFactorNode (_bsdf->plastic .specularTransmittance ,ECommonDebug::MitsubaExtraFactor);
849+ trans->rhs = mul (fresnelH,factorH);
829850 }
830851 leaf->btdf = transH;
831852 const auto substrateH = frontPool.emplace <frontend_ir_t ::CLayer>();
@@ -865,67 +886,172 @@ auto SContext::genMaterial(const CElementBSDF* bsdf, system::ISystem* debugFileW
865886 }
866887 default :
867888 assert (false ); // we shouldn't get this case here
868- return errorMaterial._const_cast ();
889+ retval = errorMaterial._const_cast ();
890+ break ;
869891 }
892+ leaf = frontPool.deref (retval);
893+ assert (leaf->brdfTop );
870894 assert (!leaf->brdfBottom );
871895 return retval;
872896 };
873897
874898 // Post-order Depth First Traversal (create children first, then create parent)
875899 struct SStackEntry
876900 {
901+ enum class ExpectedNodeType : uint64_t
902+ {
903+ Layer,
904+ Count
905+ };
877906 const CElementBSDF* bsdf;
907+ ExpectedNodeType expectedNodeType : 2 = ExpectedNodeType::Layer;
878908 uint64_t visited : 1 = false ;
879- uint64_t expectedNodeType : 2 = false ;
880- uint64_t unused : 61 = false ;
909+ uint64_t unused : 61 = 0 ;
881910 };
882911 core::vector<SStackEntry> stack;
883912 stack.reserve (128 );
884- stack.emplace_back () = {
885- .bsdf = bsdf
886- };
913+ stack.emplace_back () = {.bsdf =bsdf};
887914 // for the static casts of handles
888915 using block_allocator_t = frontend_ir_t ::obj_pool_type::mem_pool_type::block_allocator_type;
889916 using node_t = frontend_ir_t ::typed_pointer_type<frontend_ir_t ::INode>;
917+ using expected_e = SStackEntry::ExpectedNodeType;
918+ const node_t errorNodes[size_t (expected_e::Count)] = {errorMaterial}; // TODO: {errorFactor,errorBRDF,errorLayer}
890919 core::unordered_map<const CElementBSDF*,node_t > localCache;
891- while (!stack.front ().visited )
920+ localCache.reserve (16 );
921+ //
922+ while (!stack.empty ())
892923 {
893- const auto entry = stack.back ();
894- assert (entry.bsdf );
895- if (!entry.visited )
924+ auto & entry = stack.back ();
925+ const auto * const _bsdf = entry.bsdf ;
926+ assert (_bsdf);
927+ // we only do post-dfs for non-leafs
928+ if (_bsdf->isMeta () && !entry.visited )
929+ {
930+ if (_bsdf->isMeta ())
931+ {
932+ const auto & meta_common = _bsdf->meta_common ;
933+ assert (meta_common.childCount );
934+ switch (_bsdf->type )
935+ {
936+ case CElementBSDF::COATING: [[fallthrough]];
937+ case CElementBSDF::ROUGHCOATING: [[fallthrough]];
938+ case CElementBSDF::MASK:
939+ {
940+ assert (meta_common.childCount ==1 );
941+ stack.emplace_back () = {.bsdf =meta_common.bsdf [0 ],.expectedNodeType =expected_e::Layer};
942+ break ;
943+ }
944+ case CElementBSDF::BUMPMAP:
945+ {
946+ assert (false ); // unimplemented
947+ break ;
948+ }
949+ case CElementBSDF::NORMALMAP:
950+ {
951+ assert (false ); // unimplemented
952+ break ;
953+ }
954+ case CElementBSDF::MIXTURE_BSDF:
955+ {
956+ assert (false ); // unimplemented
957+ break ;
958+ }
959+ case CElementBSDF::BLEND_BSDF:
960+ {
961+ assert (false ); // unimplemented
962+ break ;
963+ }
964+ case CElementBSDF::TWO_SIDED:
965+ {
966+ assert (meta_common.childCount <=2 );
967+ stack.emplace_back () = {.bsdf =meta_common.bsdf [0 ],.expectedNodeType =expected_e::Layer};
968+ assert (false ); // unimplemented
969+ break ;
970+ }
971+ default :
972+ assert (false ); // we shouldn't get this case here
973+ break ;
974+ }
975+ }
976+ entry.visited = true ;
977+ }
978+ else
896979 {
897- node_t newNodeH = {}; // TODO: {errorFactor,errorBRDF,errorLayer}[entry.expectedNodeType];
898- if (entry. bsdf ->isMeta ())
980+ node_t newNodeH = {};
981+ if (_bsdf ->isMeta ())
899982 {
900- return errorMaterial;// temporary
901- switch (entry.bsdf ->type )
983+ switch (_bsdf->type )
902984 {
985+ case CElementBSDF::COATING: [[fallthrough]];
986+ case CElementBSDF::ROUGHCOATING:
987+ {
988+ const auto coatingH = frontPool.emplace <frontend_ir_t ::CLayer>();
989+ auto * const coating = frontPool.deref (coatingH);
990+ // create BRDF thats cook torrance
991+ // TODO
992+ // BTDF thats transmission with absorption
993+ // TODO
994+ // attach leaf as layer
995+ coating->coated = block_allocator_t ::_static_cast<frontend_ir_t ::CLayer>(localCache[_bsdf->mask .bsdf [0 ]]);
996+ newNodeH = coatingH;
997+ break ;
998+ }
903999 case CElementBSDF::MASK:
9041000 {
905- const auto maskH = createFactorNode (entry. bsdf -> mask . opacity ,ECommonDebug::Opacity );
1001+ const auto maskH = frontPool. emplace < frontend_ir_t ::CLayer>( );
9061002 auto * const mask = frontPool.deref (maskH);
907- // mask->lhs = ;
1003+ //
1004+ const auto nestedH = block_allocator_t ::_static_cast<frontend_ir_t ::CLayer>(localCache[_bsdf->mask .bsdf [0 ]]);
1005+ auto * const nested = frontPool.deref (nestedH);
1006+ assert (nested && nested->brdfTop );
1007+ const auto opacityH = createFactorNode (_bsdf->mask .opacity ,ECommonDebug::Opacity);
1008+ mask->brdfTop = mul (nested->brdfTop ,opacityH);
1009+ {
1010+ const auto transparencyH = frontPool.emplace <frontend_ir_t ::CComplement>();
1011+ frontPool.deref (transparencyH)->child = opacityH;
1012+ mask->btdf = add (mul (deltaTransmission._const_cast (),transparencyH),mul (nested->btdf ,opacityH));
1013+ }
1014+ mask->brdfBottom = mul (nested->brdfBottom ,opacityH);
9081015 newNodeH = maskH;
9091016 break ;
9101017 }
911- // case CElementBSDF::TWO_SIDED:
1018+ case CElementBSDF::BUMPMAP:
1019+ {
1020+ assert (false ); // unimplemented
1021+ break ;
1022+ }
1023+ case CElementBSDF::NORMALMAP:
1024+ {
1025+ assert (false ); // unimplemented
1026+ break ;
1027+ }
1028+ case CElementBSDF::MIXTURE_BSDF:
1029+ {
1030+ assert (false ); // unimplemented
1031+ break ;
1032+ }
1033+ case CElementBSDF::BLEND_BSDF:
1034+ {
1035+ assert (false ); // unimplemented
1036+ break ;
1037+ }
1038+ case CElementBSDF::TWO_SIDED:
1039+ {
1040+ // create a copy of the layer, with different settings (don't want to disturb the original)
9121041 // 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
913- // break;
1042+ assert (false ); // unimplemented
1043+ break ;
1044+ }
9141045 default :
9151046 assert (false ); // we shouldn't get this case here
9161047 break ;
9171048 }
9181049 }
9191050 else
920- {
921- newNodeH = createMistubaLeaf (entry.bsdf );
922- // have to make it available somehow for parent
923- }
924- localCache[entry.bsdf ] = newNodeH;
925- stack.back ().visited = true ;
926- }
927- else
928- {
1051+ newNodeH = createMistubaLeaf (_bsdf);
1052+ if (!newNodeH)
1053+ newNodeH = errorNodes[size_t (entry.expectedNodeType )];
1054+ localCache[_bsdf] = newNodeH;
9291055 stack.pop_back ();
9301056 }
9311057 }
@@ -1096,6 +1222,7 @@ SContext::SContext(
10961222 {
10971223#define ADD_DEBUG_NODE (NAME ) commonDebugNames[uint16_t (ECommonDebug::NAME)] = frontPool.emplace<frontend_ir_t ::CDebugInfo>(#NAME)
10981224 ADD_DEBUG_NODE (Albedo);
1225+ ADD_DEBUG_NODE (Weight);
10991226 ADD_DEBUG_NODE (Opacity);
11001227 ADD_DEBUG_NODE (MitsubaExtraFactor);
11011228#undef ADD_DEBUG_NODE
0 commit comments