1
- // Copyright (C) 2022-2025 - DevSH Graphics Programming Sp. z O.O.
1
+ // Copyright (C) 2022-2025 - DevSH Graphics Programming Sp. z O.O.
2
2
// This file is part of the "Nabla Engine".
3
3
// For conditions of distribution and use, see copyright notice in nabla.h
4
4
#ifndef _NBL_ASSET_MATERIAL_COMPILER_V3_C_FRONTEND_IR_H_INCLUDED_
@@ -113,6 +113,18 @@ class CFrontendIR : public CNodePool
113
113
{
114
114
return abs (scale)<std::numeric_limits<float >::infinity () && (!view || viewChannel<getFormatChannelCount (view->getCreationParameters ().format ));
115
115
}
116
+ inline bool operator !=(const SParameter& other) const
117
+ {
118
+ if (scale!=other.scale )
119
+ return true ;
120
+ if (viewChannel!=other.viewChannel )
121
+ return true ;
122
+ // don't compare paddings!
123
+ if (view!=other.view )
124
+ return true ;
125
+ return sampler!=other.sampler ;
126
+ }
127
+ inline bool operator ==(const SParameter& other) const {return !operator !=(other);}
116
128
117
129
NBL_API void printDot (std::ostringstream& sstr, const core::string& selfID) const ;
118
130
@@ -123,6 +135,7 @@ class CFrontendIR : public CNodePool
123
135
uint8_t padding[3 ] = {0 ,0 ,0 };
124
136
core::smart_refctd_ptr<const ICPUImageView> view = {};
125
137
// shadow comparison functions are ignored
138
+ // NOTE: could take only things that matter from the sampler and pack the viewChannel and reduce padding
126
139
ICPUSampler::SParams sampler = {};
127
140
};
128
141
// In the forest, this is not a node, we'll deduplicate later
@@ -132,7 +145,7 @@ class CFrontendIR : public CNodePool
132
145
private:
133
146
friend class CSpectralVariable ;
134
147
template <typename StringConstIterator=const core::string*>
135
- inline void printDot (const uint8_t _count, std::ostringstream& sstr, const core::string& selfID, StringConstIterator paramNameBegin={}) const
148
+ inline void printDot (const uint8_t _count, std::ostringstream& sstr, const core::string& selfID, StringConstIterator paramNameBegin={}, const bool uvRequired= false ) const
136
149
{
137
150
bool imageUsed = false ;
138
151
for (uint8_t i=0 ; i<_count; i++)
@@ -147,10 +160,10 @@ class CFrontendIR : public CNodePool
147
160
else
148
161
sstr <<" [label=\" Param " << std::to_string (i) <<" \" ]" ;
149
162
}
150
- if (imageUsed)
163
+ if (uvRequired || imageUsed)
151
164
{
152
165
const auto uvTransformID = selfID+" _uvTransform" ;
153
- sstr << " \n\t " << uvTransformID << " [label=\" " ;
166
+ sstr << " \n\t " << uvTransformID << " [label=\" uvSlot = " << std::to_string ( uvSlot ()) << " \\ n " ;
154
167
printMatrix (sstr,*reinterpret_cast <const decltype (uvTransform)*>(params+_count));
155
168
sstr << " \" ]" ;
156
169
sstr << " \n\t " << selfID << " -> " << uvTransformID << " [label=\" UV Transform\" ]" ;
@@ -165,20 +178,21 @@ class CFrontendIR : public CNodePool
165
178
return false ;
166
179
return true ;
167
180
}
168
- // Ignored if no modulator textures
181
+ // Ignored if no modulator textures and isotropic BxDF
169
182
uint8_t & uvSlot () {return params[0 ].padding [0 ];}
170
183
const uint8_t & uvSlot () const {return params[0 ].padding [0 ];}
171
184
// Note: the padding abuse
172
185
static_assert (sizeof (SParameter::padding)>0 );
173
186
174
187
template <typename StringConstIterator=const core::string*>
175
- inline void printDot (std::ostringstream& sstr, const core::string& selfID, StringConstIterator paramNameBegin={}) const
188
+ inline void printDot (std::ostringstream& sstr, const core::string& selfID, StringConstIterator paramNameBegin={}, const bool uvRequired= false ) const
176
189
{
177
- printDot<StringConstIterator>(Count,sstr,selfID,std::forward<StringConstIterator>(paramNameBegin));
190
+ printDot<StringConstIterator>(Count,sstr,selfID,std::forward<StringConstIterator>(paramNameBegin),uvRequired );
178
191
}
179
192
180
193
SParameter params[Count] = {};
181
194
// identity transform by default, ignored if no UVs
195
+ // NOTE: a transform could be applied per-param, whats important that the UV slot remains the smae across all of them.
182
196
hlsl::float32_t2x3 uvTransform = hlsl::float32_t2x3(
183
197
1 ,0 ,0 ,
184
198
0 ,1 ,0
@@ -280,6 +294,7 @@ class CFrontendIR : public CNodePool
280
294
virtual _TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const = 0;
281
295
282
296
virtual inline core::string getLabelSuffix () const {return " " ;}
297
+ virtual inline std::string_view getChildName_impl (const uint8_t ix) const {return " " ;}
283
298
virtual inline void printDot (std::ostringstream& sstr, const core::string& selfID) const {}
284
299
};
285
300
@@ -443,6 +458,7 @@ class CFrontendIR : public CNodePool
443
458
{
444
459
protected:
445
460
inline TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const override final {return ix ? rhs:lhs;}
461
+ inline std::string_view getChildName_impl (const uint8_t ix) const override final {return ix ? " rhs" :" lhs" ;}
446
462
447
463
public:
448
464
inline uint8_t getChildCount () const override final {return 2 ;}
@@ -493,6 +509,8 @@ class CFrontendIR : public CNodePool
493
509
protected:
494
510
inline TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const override final {return ix ? (ix!=1 ? extinction:transmittance):reflectance;}
495
511
NBL_API bool invalid (const SInvalidCheckArgs& args) const override ;
512
+
513
+ inline std::string_view getChildName_impl (const uint8_t ix) const override {return ix ? (ix>1 ? " extinction" :" reflectance" ):" transmittance" ;}
496
514
inline void printDot (std::ostringstream& sstr, const core::string& selfID) const override
497
515
{
498
516
sstr << " \n\t " << selfID << " -> " << selfID << " _computeTransmittance [label=\" computeTransmittance = " << (computeTransmittance ? " true" :" false" ) << " \" ]" ;
@@ -563,13 +581,15 @@ class CFrontendIR : public CNodePool
563
581
inline uint32_t getSize () const override {return calc_size ();}
564
582
inline CBeer () = default;
565
583
566
- // Effective transparency = exp2(log2(perpTransparency )/dot(refract(V,X,eta),X)) = exp2(log2(perpTransparency )*inversesqrt(1.f+(LdotX-1)*rcpEta))
584
+ // Effective transparency = exp2(log2(perpTransmittance )/dot(refract(V,X,eta),X)) = exp2(log2(perpTransmittance )*inversesqrt(1.f+(LdotX-1)*rcpEta))
567
585
// Absorption and thickness of the interface combined into a single variable, eta and `LdotX` is taken from the leaf BTDF node.
568
586
// With refractions from Dielectrics, we get just `1/LdotX`, for Delta Transmission we get `1/VdotN` since its the same
569
- TypedHandle<CSpectralVariable> perpTransparency = {};
587
+ TypedHandle<CSpectralVariable> perpTransmittance = {};
570
588
571
589
protected:
572
- inline TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return perpTransparency;}
590
+ inline TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return perpTransmittance;}
591
+
592
+ inline std::string_view getChildName_impl (const uint8_t ix) const override {return " Perpendicular\\ nTransmittance" ;}
573
593
NBL_API bool invalid (const SInvalidCheckArgs& args) const override ;
574
594
};
575
595
// The "oriented" in the Etas means from frontface to backface, so there's no need to reciprocate them when creating matching BTDF for BRDF
@@ -593,6 +613,7 @@ class CFrontendIR : public CNodePool
593
613
protected:
594
614
inline TypedHandle<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return ix ? orientedImagEta:orientedRealEta;}
595
615
NBL_API bool invalid (const SInvalidCheckArgs& args) const override ;
616
+ inline std::string_view getChildName_impl (const uint8_t ix) const override {return ix ? " Real" :" Imaginary" ;}
596
617
NBL_API void printDot (std::ostringstream& sstr, const core::string& selfID) const override ;
597
618
};
598
619
// @kept_secret TODO: Thin Film Interference Fresnel
@@ -618,6 +639,19 @@ class CFrontendIR : public CNodePool
618
639
param.scale = 0 .f ;
619
640
}
620
641
642
+ // conservative check, checks if we can optimize certain things this way
643
+ inline bool definitelyIsotropic () const
644
+ {
645
+ // a derivative map from a texture allows for anisotropic NDFs at higher mip levels when pre-filtered properly
646
+ for (auto i=0 ; i<2 ; i++)
647
+ if (getDerivMap ()[i].scale !=0 .f && getDerivMap ()[i].view )
648
+ return false ;
649
+ // if roughness inputs are not equal (same scale, same texture) then NDF can be anisotropic in places
650
+ if (getRougness ()[0 ]!=getRougness ()[1 ])
651
+ return false ;
652
+ // if a reference stretch is used, stretched triangles can turn the distribution isotropic
653
+ return stretchInvariant ();
654
+ }
621
655
// whether the derivative map and roughness is constant regardless of UV-space texture stretching
622
656
inline bool stretchInvariant () const {return !(abs (hlsl::determinant (reference))>std::numeric_limits<float >::min ());}
623
657
@@ -704,6 +738,7 @@ class CFrontendIR : public CNodePool
704
738
NBL_API bool invalid (const SInvalidCheckArgs& args) const override ;
705
739
706
740
inline core::string getLabelSuffix () const override {return ndf!=NDF::GGX ? " \\ nNDF = Beckmann" :" \\ nNDF = GGX" ;}
741
+ inline std::string_view getChildName_impl (const uint8_t ix) const override {return " Oriented η" ;}
707
742
NBL_API void printDot (std::ostringstream& sstr, const core::string& selfID) const override ;
708
743
};
709
744
0 commit comments