@@ -313,8 +313,9 @@ NBL_CONCEPT_BEGIN(2)
313313NBL_CONCEPT_END (
314314 ((NBL_CONCEPT_REQ_TYPE)(T::scalar_type))
315315 ((NBL_CONCEPT_REQ_TYPE)(T::vector_type))
316+ ((NBL_CONCEPT_REQ_TYPE)(T::eta_type))
316317 ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((fresnel (cosTheta)), ::nbl::hlsl::is_same_v, typename T::vector_type))
317- ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((fresnel.getOrientedEtaRcps ()), ::nbl::hlsl::is_same_v, OrientedEtaRcps<typename T::vector_type >))
318+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((fresnel.getOrientedEtaRcps ()), ::nbl::hlsl::is_same_v, OrientedEtaRcps<typename T::eta_type >))
318319);
319320#undef cosTheta
320321#undef fresnel
@@ -342,6 +343,7 @@ struct Schlick
342343{
343344 using scalar_type = typename vector_traits<T>::scalar_type;
344345 using vector_type = T;
346+ using eta_type = vector_type;
345347
346348 static Schlick<T> create (NBL_CONST_REF_ARG (T) F0)
347349 {
@@ -358,11 +360,11 @@ struct Schlick
358360 return F0 + (1.0 - F0) * x*x*x*x*x;
359361 }
360362
361- OrientedEtaRcps<T > getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
363+ OrientedEtaRcps<eta_type > getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
362364 {
363- const T sqrtF0 = hlsl::sqrt (F0);
364- OrientedEtaRcps<T > rcpEta;
365- rcpEta.value = (hlsl::promote<T >(1.0 ) - sqrtF0) / (hlsl::promote<T >(1.0 ) + sqrtF0);
365+ const eta_type sqrtF0 = hlsl::sqrt (F0);
366+ OrientedEtaRcps<eta_type > rcpEta;
367+ rcpEta.value = (hlsl::promote<eta_type >(1.0 ) - sqrtF0) / (hlsl::promote<eta_type >(1.0 ) + sqrtF0);
366368 rcpEta.value2 = rcpEta.value * rcpEta.value;
367369 return rcpEta;
368370 }
@@ -375,6 +377,7 @@ struct Conductor
375377{
376378 using scalar_type = typename vector_traits<T>::scalar_type;
377379 using vector_type = T;
380+ using eta_type = vector_type;
378381
379382 static Conductor<T> create (NBL_CONST_REF_ARG (T) eta, NBL_CONST_REF_ARG (T) etak)
380383 {
@@ -432,10 +435,10 @@ struct Conductor
432435 return (rs2 + rp2) * hlsl::promote<T>(0.5 );
433436 }
434437
435- OrientedEtaRcps<T > getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
438+ OrientedEtaRcps<eta_type > getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
436439 {
437- OrientedEtaRcps<T > rcpEta;
438- rcpEta.value = hlsl::promote<T >(1.0 ) / eta;
440+ OrientedEtaRcps<eta_type > rcpEta;
441+ rcpEta.value = hlsl::promote<eta_type >(1.0 ) / eta;
439442 rcpEta.value2 = rcpEta.value * rcpEta.value;
440443 return rcpEta;
441444 }
@@ -450,6 +453,7 @@ struct Dielectric
450453{
451454 using scalar_type = typename vector_traits<T>::scalar_type;
452455 using vector_type = T;
456+ using eta_type = vector_type;
453457
454458 static Dielectric<T> create (NBL_CONST_REF_ARG (OrientedEtas<T>) orientedEta)
455459 {
@@ -510,26 +514,16 @@ struct Dielectric
510514};
511515
512516// adapted from https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
517+ template<typename T, bool SupportsTransmission NBL_STRUCT_CONSTRAINABLE>
518+ struct Iridescent;
519+
520+ namespace impl
521+ {
513522template<typename T, bool SupportsTransmission NBL_PRIMARY_REQUIRES (concepts::FloatingPointLikeVectorial<T>)
514- struct Iridescent
523+ struct iridescent_helper
515524{
516- using this_t = Iridescent<T,SupportsTransmission>;
517525 using scalar_type = typename vector_traits<T>::scalar_type;
518- using monochrome_type = vector <scalar_type, 1 >;
519- using vector_type = T; // assert dim==3?
520-
521- static this_t create (scalar_type Dinc, vector_type ior1, vector_type ior2, vector_type ior3, vector_type iork3)
522- {
523- this_t retval;
524- retval.Dinc = Dinc;
525- retval.thinFilmIor = ior2;
526- retval.eta12 = ior2/ior1;
527- retval.eta23 = ior3/ior2;
528- retval.etak23 = scalar_type (0.0 );
529- NBL_IF_CONSTEXPR (SupportsTransmission)
530- retval.etak23 = iork3/ior2;
531- return retval;
532- }
526+ using vector_type = T;
533527
534528 // returns reflectance R = (rp, rs), phi is the phase shift for each plane of polarization (p,s)
535529 static void phase_shift (const vector_type orientedEta, const vector_type orientedEtak, const vector_type cosTheta, NBL_REF_ARG (vector_type) phiS, NBL_REF_ARG (vector_type) phiP)
@@ -566,7 +560,7 @@ struct Iridescent
566560 return xyz / scalar_type (1. 0685e-7 );
567561 }
568562
569- T operator ()( const scalar_type clampedCosTheta /* LdotH */ )
563+ T __call ( const scalar_type clampedCosTheta)
570564 {
571565 const vector_type wavelengths = vector_type (colorspace::scRGB::wavelength_R, colorspace::scRGB::wavelength_G, colorspace::scRGB::wavelength_B);
572566
@@ -646,11 +640,80 @@ struct Iridescent
646640 return hlsl::max (colorspace::scRGB::FromXYZ (I), hlsl::promote<vector_type>(0.0 )) * hlsl::promote<vector_type>(0.5 );
647641 }
648642
649- scalar_type getRefractionOrientedEta () NBL_CONST_MEMBER_FUNC { return eta23[0 ]; }
650- OrientedEtaRcps<monochrome_type> getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
643+ scalar_type Dinc; // thickness of thin film in nanometers, rec. 100-25000nm
644+ vector_type thinFilmIor;
645+ vector_type eta12; // outside (usually air 1.0) -> thin-film IOR
646+ vector_type eta23; // thin-film -> base material IOR
647+ vector_type etak23; // thin-film -> complex component, k==0 makes dielectric
648+ };
649+ }
650+
651+ template<typename T>
652+ NBL_PARTIAL_REQ_TOP (concepts::FloatingPointLikeVectorial<T>)
653+ struct Iridescent<T, false NBL_PARTIAL_REQ_BOT (concepts::FloatingPointLikeVectorial<T>) >
654+ {
655+ using this_t = Iridescent<T,false >;
656+ using scalar_type = typename vector_traits<T>::scalar_type;
657+ using vector_type = T; // assert dim==3?
658+ using eta_type = vector_type;
659+
660+ static this_t create (scalar_type Dinc, vector_type ior1, vector_type ior2, vector_type ior3, vector_type iork3)
661+ {
662+ this_t retval;
663+ retval.helper.Dinc = Dinc;
664+ retval.helper.thinFilmIor = ior2;
665+ retval.helper.eta12 = ior2/ior1;
666+ retval.helper.eta23 = ior3/ior2;
667+ retval.helper.etak23 = iork3/ior2;
668+ return retval;
669+ }
670+
671+ T operator ()(const scalar_type clampedCosTheta)
672+ {
673+ return helper.__call (clampedCosTheta);
674+ }
675+
676+ OrientedEtaRcps<eta_type> getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
677+ {
678+ OrientedEtaRcps<eta_type> rcpEta;
679+ rcpEta.value = hlsl::promote<eta_type>(1.0 ) / helper.eta23;
680+ rcpEta.value2 = rcpEta.value * rcpEta.value;
681+ return rcpEta;
682+ }
683+
684+ impl::iridescent_helper<T,false > helper;
685+ };
686+
687+ template<typename T>
688+ NBL_PARTIAL_REQ_TOP (concepts::FloatingPointLikeVectorial<T>)
689+ struct Iridescent<T, true NBL_PARTIAL_REQ_BOT (concepts::FloatingPointLikeVectorial<T>) >
690+ {
691+ using this_t = Iridescent<T,true >;
692+ using scalar_type = typename vector_traits<T>::scalar_type;
693+ using vector_type = T; // assert dim==3?
694+ using eta_type = vector <scalar_type, 1 >;
695+
696+ static this_t create (scalar_type Dinc, vector_type ior1, vector_type ior2, vector_type ior3)
651697 {
652- OrientedEtaRcps<monochrome_type> rcpEta;
653- rcpEta.value = hlsl::promote<monochrome_type>(1.0 ) / eta23[0 ];
698+ this_t retval;
699+ retval.helper.Dinc = Dinc;
700+ retval.helper.thinFilmIor = ior2;
701+ retval.helper.eta12 = ior2/ior1;
702+ retval.helper.eta23 = ior3/ior2;
703+ retval.helper.etak23 = hlsl::promote<vector_type>(0.0 );
704+ return retval;
705+ }
706+
707+ T operator ()(const scalar_type clampedCosTheta)
708+ {
709+ return helper.__call (clampedCosTheta);
710+ }
711+
712+ scalar_type getRefractionOrientedEta () NBL_CONST_MEMBER_FUNC { return helper.eta23[0 ]; }
713+ OrientedEtaRcps<eta_type> getOrientedEtaRcps () NBL_CONST_MEMBER_FUNC
714+ {
715+ OrientedEtaRcps<eta_type> rcpEta;
716+ rcpEta.value = hlsl::promote<eta_type>(1.0 ) / helper.eta23[0 ];
654717 rcpEta.value2 = rcpEta.value * rcpEta.value;
655718 return rcpEta;
656719 }
@@ -659,21 +722,15 @@ struct Iridescent
659722 {
660723 const bool flip = NdotI < scalar_type (0.0 );
661724 this_t orientedFresnel;
662- orientedFresnel.Dinc = Dinc;
663- orientedFresnel.thinFilmIor = thinFilmIor;
664- orientedFresnel.eta12 = hlsl::mix (eta12, hlsl::promote<vector_type>(1.0 )/eta12, flip);
665- orientedFresnel.eta23 = hlsl::mix (eta23, hlsl::promote<vector_type>(1.0 )/eta23, flip);
666- orientedFresnel.etak23 = hlsl::promote<vector_type>(0.0 );
667- NBL_IF_CONSTEXPR (SupportsTransmission)
668- orientedFresnel.etak23 = hlsl::mix (etak23, hlsl::promote<vector_type>(1.0 )/etak23, flip);
725+ orientedFresnel.helper.Dinc = helper.Dinc;
726+ orientedFresnel.helper.thinFilmIor = helper.thinFilmIor;
727+ orientedFresnel.helper.eta12 = hlsl::mix (helper.eta12, hlsl::promote<vector_type>(1.0 )/helper.eta12, flip);
728+ orientedFresnel.helper.eta23 = hlsl::mix (helper.eta23, hlsl::promote<vector_type>(1.0 )/helper.eta23, flip);
729+ orientedFresnel.helper.etak23 = hlsl::promote<vector_type>(0.0 );
669730 return orientedFresnel;
670731 }
671732
672- scalar_type Dinc; // thickness of thin film in nanometers, rec. 100-25000nm
673- vector_type thinFilmIor;
674- vector_type eta12; // outside (usually air 1.0) -> thin-film IOR
675- vector_type eta23; // thin-film -> base material IOR
676- vector_type etak23; // thin-film -> complex component, k==0 makes dielectric
733+ impl::iridescent_helper<T,true > helper;
677734};
678735
679736
0 commit comments