Skip to content

Commit 1477269

Browse files
Refactor and unify the SpectralVariable in the IR and AST, I'm pleased with how it looks now
1 parent edb8750 commit 1477269

7 files changed

Lines changed: 354 additions & 312 deletions

File tree

examples_tests

include/nbl/asset/material_compiler3/CFrontendIR.h

Lines changed: 30 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -220,151 +220,36 @@ class CFrontendIR final : public CNodePool
220220
};
221221

222222
// This node could also represent non directional emission, but we have another node for that
223-
class CSpectralVariable final : public obj_pool_type::IVariableSize, public IExprNode
223+
class ISpectralVariableExpr : public CTrueIR::ISpectralVariable, public IExprNode
224224
{
225225
public:
226-
inline uint8_t getChildCount() const override final { return 0; }
227-
inline const std::string_view getTypeName() const override {return TYPE_NAME_STR(CSpectralVariable);}
228226
// Variable length but has no children
227+
inline uint8_t getChildCount() const override final {return 0;}
229228

230229
//
231-
inline IExprNode::Type getType() const override {return Type::SpectralVariable;}
230+
inline IExprNode::Type getType() const override final {return Type::SpectralVariable;}
232231

233-
using semantics_e = CTrueIR::ISpectralVariable::ESemantics;
234232
//
235-
template<uint8_t Count>
236-
struct SCreationParams
237-
{
238-
// Knots are "data points" on the (wavelength,value) plot, from which we can interpolate the rest of the spectrum
239-
CTrueIR::SParameterSet<Count> knots = {};
240-
241-
// a little bit of abuse and padding reuse
242-
template<bool Enable=true> requires (Enable==(Count>1))
243-
semantics_e& getSemantics() {return reinterpret_cast<semantics_e&>(knots.params[1].padding[0]); }
244-
template<bool Enable=true> requires (Enable==(Count>1))
245-
const semantics_e& getSemantics() const {return const_cast<const semantics_e&>(const_cast<SCreationParams<Count>*>(this)->getSemantics());}
246-
};
247-
//
248-
template<uint8_t Count>
249-
inline CSpectralVariable(SCreationParams<Count>&& params)
250-
{
251-
// back up the count
252-
static_assert(sizeof(CTrueIR::SParameter::padding)>1);
253-
params.knots.params[0].padding[1] = Count;
254-
// set it correctly for monochrome
255-
if constexpr (Count==1)
256-
params.knots.params[1].padding[0] = static_cast<uint8_t>(semantics_e::NoneUndefined);
257-
else
258-
{
259-
assert(params.getSemantics()!=semantics_e::NoneUndefined);
260-
}
261-
std::construct_at(reinterpret_cast<SCreationParams<Count>*>(this+1),std::move(params));
262-
}
263-
inline CSpectralVariable(const CSpectralVariable& other)
264-
{
265-
const auto* const src = other.pWonky();
266-
auto* const dst = pWonky();
267-
std::uninitialized_copy_n(src,1,dst);
268-
const size_t count = other.getKnotCount();
269-
std::uninitialized_copy_n(src->knots.params+1,count-1,dst->knots.params+1);
270-
}
271-
272-
// encapsulation due to padding abuse
273-
inline auto& uvTransform() {return pWonky()->knots.uvTransform;}
274-
inline const auto& uvTransform() const {return pWonky()->knots.uvTransform;}
275-
276-
inline uint8_t& uvSlot() {return pWonky()->knots.uvSlot();}
277-
inline const uint8_t& uvSlot() const {return pWonky()->knots.uvSlot();}
278-
279-
// these getters are immutable
280-
inline uint8_t getKnotCount() const
281-
{
282-
static_assert(sizeof(CTrueIR::SParameter::padding)>1);
283-
return pWonky()->knots.params[0].padding[1];
284-
}
285-
inline semantics_e getSemantics() const
286-
{
287-
if (getKnotCount()<2)
288-
return semantics_e::NoneUndefined;
289-
return static_cast<semantics_e>(pWonky()->knots.params[1].padding[0]);
290-
}
291-
292-
//
293-
inline CTrueIR::SParameter* getParam(const uint8_t i)
294-
{
295-
if (i<getKnotCount())
296-
return &pWonky()->knots.params[i];
297-
return nullptr;
298-
}
299-
inline const CTrueIR::SParameter* getParam(const uint8_t i) const {return const_cast<const CTrueIR::SParameter*>(const_cast<CSpectralVariable*>(this)->getParam(i));}
300-
301-
//
302-
template<uint8_t Count>
303-
static inline uint32_t calc_size(const SCreationParams<Count>&)
304-
{
305-
return sizeof(CSpectralVariable)+sizeof(SCreationParams<Count>);
306-
}
307-
// for copying
308-
static inline uint32_t calc_size(const CSpectralVariable& other)
309-
{
310-
return sizeof(CSpectralVariable)+sizeof(SCreationParams<1>)+(other.getKnotCount()-1)*sizeof(CTrueIR::SParameter);
311-
}
312-
313-
inline operator bool() const {return !invalid(SInvalidCheckArgs{.pool=nullptr,.logger=nullptr});}
233+
inline operator bool() const {return valid(nullptr);}
314234

315235
protected:
316-
inline ~CSpectralVariable()
317-
{
318-
std::destroy_n(pWonky()->knots.params,getKnotCount());
319-
}
320236
inline _typed_pointer_type<IExprNode> copy(CFrontendIR* ir) const override final
321237
{
322-
auto& pool = ir->getObjectPool();
323-
const uint8_t count = getKnotCount();
324-
return pool.emplace<CSpectralVariable>(*this);
238+
return static_cast<const CSpectralVariableExpr*>(this)->copy(ir->getObjectPool());
325239
}
326240

327-
inline bool invalid(const SInvalidCheckArgs& args) const override
328-
{
329-
const auto knotCount = getKnotCount();
330-
// non-monochrome spectral variable
331-
if (const auto semantic=getSemantics(); knotCount>1)
332-
switch (semantic)
333-
{
334-
case semantics_e::Fixed3_SRGB: [[fallthrough]];
335-
case semantics_e::Fixed3_DCI_P3: [[fallthrough]];
336-
case semantics_e::Fixed3_BT2020: [[fallthrough]];
337-
case semantics_e::Fixed3_AdobeRGB: [[fallthrough]];
338-
case semantics_e::Fixed3_AcesCG:
339-
if (knotCount!=3)
340-
{
341-
args.logger.log("Semantic %d is only usable with 3 knots, this has %d knots",system::ILogger::ELL_ERROR,static_cast<uint8_t>(semantic),knotCount);
342-
return false;
343-
}
344-
break;
345-
default:
346-
args.logger.log("Invalid Semantic %d",system::ILogger::ELL_ERROR,static_cast<uint8_t>(semantic));
347-
return true;
348-
}
349-
for (auto i=0u; i<knotCount; i++)
350-
if (!*getParam(i))
351-
{
352-
args.logger.log("Knot %u parameters invalid",system::ILogger::ELL_ERROR,i);
353-
return true;
354-
}
355-
return false;
356-
}
241+
//
242+
inline bool invalid(const SInvalidCheckArgs& args) const override final {return !valid(args.logger);}
357243

358-
NBL_API2 core::string getLabelSuffix() const override;
359-
NBL_API2 void printDot(std::ostringstream& sstr, const core::string& selfID) const override;
360-
361-
private:
362-
SCreationParams<1>* pWonky() {return reinterpret_cast<SCreationParams<1>*>(this+1);}
363-
const SCreationParams<1>* pWonky() const {return reinterpret_cast<const SCreationParams<1>*>(this+1);}
244+
//
245+
NBL_API2 core::string getLabelSuffix() const override final;
246+
NBL_API2 void printDot(std::ostringstream& sstr, const core::string& selfID) const override final;
364247

248+
//
365249
friend class CFrontendIR;
366-
NBL_API2 CTrueIR::typed_pointer_type<CTrueIR::ISpectralVariable> createIRNode(const CFrontendIR* ast, CTrueIR* ir) const;
250+
NBL_API2 CTrueIR::typed_pointer_type<CTrueIR::CSpectralVariableFactor> createIRNode(const CFrontendIR* ast, CTrueIR* ir) const;
367251
};
252+
using CSpectralVariableExpr = CTrueIR::CSpectralVariable<ISpectralVariableExpr>;
368253
//
369254
class IUnaryOp : public obj_pool_type::INonTrivial, public IExprNode
370255
{
@@ -483,16 +368,16 @@ class CFrontendIR final : public CNodePool
483368

484369
// Effective transparency = exp2(log2(perpTransmittance)*thickness/dot(refract(V,X,eta),X)) = exp2(log2(perpTransmittance)*thickness*inversesqrt(1.f+(LdotX-1)*rcpEta))
485370
// Eta and `LdotX` is taken from the leaf BTDF node. With refractions from Dielectrics, we get just `1/LdotX`, for Delta Transmission we get `1/VdotN` since its the same
486-
typed_pointer_type<CSpectralVariable> perpTransmittance = {};
487-
typed_pointer_type<CSpectralVariable> thickness = {};
371+
typed_pointer_type<CSpectralVariableExpr> perpTransmittance = {};
372+
typed_pointer_type<CSpectralVariableExpr> thickness = {};
488373

489374
protected:
490375
COPY_DEFAULT_IMPL
491376

492377
inline typed_pointer_type<IExprNode> getChildHandle_impl(const uint8_t ix) const override {return ix ? perpTransmittance:thickness;}
493378
inline void setChild_impl(const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override
494379
{
495-
*(ix ? &perpTransmittance:&thickness) = block_allocator_type::_static_cast<CSpectralVariable>(newChild);
380+
*(ix ? &perpTransmittance:&thickness) = block_allocator_type::_static_cast<CSpectralVariableExpr>(newChild);
496381
}
497382

498383
inline std::string_view getChildName_impl(const uint8_t ix) const override {return "Perpendicular\\nTransmittance";}
@@ -509,9 +394,9 @@ class CFrontendIR final : public CNodePool
509394
inline CFresnel() = default;
510395

511396
// Already pre-divided Index of Refraction, e.g. exterior/interior since VdotG>0 the ray always arrives from the exterior.
512-
typed_pointer_type<CSpectralVariable> orientedRealEta = {};
397+
typed_pointer_type<CSpectralVariableExpr> orientedRealEta = {};
513398
// Specifying this turns your Fresnel into a conductor one, note that currently these are disallowed on BTDFs!
514-
typed_pointer_type<CSpectralVariable> orientedImagEta = {};
399+
typed_pointer_type<CSpectralVariableExpr> orientedImagEta = {};
515400
// if you want to reuse the same parameter but want to flip the interfaces around
516401
uint8_t reciprocateEtas : 1 = false;
517402

@@ -521,7 +406,7 @@ class CFrontendIR final : public CNodePool
521406
inline typed_pointer_type<IExprNode> getChildHandle_impl(const uint8_t ix) const override {return ix ? orientedImagEta:orientedRealEta;}
522407
inline void setChild_impl(const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override
523408
{
524-
*(ix ? &orientedImagEta:&orientedRealEta) = block_allocator_type::_static_cast<CSpectralVariable>(newChild);
409+
*(ix ? &orientedImagEta:&orientedRealEta) = block_allocator_type::_static_cast<CSpectralVariableExpr>(newChild);
525410
}
526411

527412
NBL_API2 bool invalid(const SInvalidCheckArgs& args) const override;
@@ -672,13 +557,13 @@ class CFrontendIR final : public CNodePool
672557

673558
CTrueIR::SBasicNDFParams ndParams = {};
674559
// See the comments in CTrueIR about this on a matching class
675-
typed_pointer_type<CSpectralVariable> orientedRealEta = {};
560+
typed_pointer_type<CSpectralVariableExpr> orientedRealEta = {};
676561

677562
protected:
678563
COPY_DEFAULT_IMPL
679564

680565
inline typed_pointer_type<IExprNode> getChildHandle_impl(const uint8_t ix) const override {return orientedRealEta;}
681-
inline void setChild_impl(const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override {orientedRealEta = block_allocator_type::_static_cast<CSpectralVariable>(newChild);}
566+
inline void setChild_impl(const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override {orientedRealEta = block_allocator_type::_static_cast<CSpectralVariableExpr>(newChild);}
682567

683568
NBL_API2 bool invalid(const SInvalidCheckArgs& args) const override;
684569

@@ -752,10 +637,14 @@ class CFrontendIR final : public CNodePool
752637
{
753638
auto& pool = getObjectPool();
754639
const auto fresnelH = pool.emplace<CFresnel>();
755-
CSpectralVariable::SCreationParams<1> params = {};
756-
params.knots.params[0].scale = orientedRealEta;
757640
if (auto* const fresnel=pool.deref(fresnelH); fresnel)
758-
fresnel->orientedRealEta = pool.emplace<CSpectralVariable>(std::move(params));
641+
{
642+
fresnel->orientedRealEta = pool.emplace<CSpectralVariableExpr>(uint8_t(1));
643+
if (auto* const var=pool.deref<CSpectralVariableExpr>(fresnel->orientedRealEta); var)
644+
var->setParameter(0,{.scale=orientedRealEta});
645+
else
646+
return {};
647+
}
759648
return fresnelH;
760649
}
761650

@@ -983,6 +872,8 @@ class CFrontendIR final : public CNodePool
983872
return retval;
984873
}
985874
};
875+
876+
template class CTrueIR::CSpectralVariable<CFrontendIR::ISpectralVariableExpr>;
986877
}
987878

988879
// specialize the `to_string

0 commit comments

Comments
 (0)