Skip to content

Commit f93f430

Browse files
get opacity going!
1 parent 1042111 commit f93f430

3 files changed

Lines changed: 185 additions & 91 deletions

File tree

include/nbl/ext/MitsubaLoader/SContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct SContext final
9595
{
9696
Albedo,
9797
Opacity,
98+
Weight,
9899
MitsubaExtraFactor,
99100
Count
100101
};

src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp

Lines changed: 177 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)