Skip to content

Conversation

@keptsecret
Copy link
Contributor

No description provided.

Base automatically changed from hlsl_bxdfs to master August 29, 2025 13:04
@keptsecret keptsecret changed the base branch from master to bxdf_fixes_cook_torrance November 3, 2025 04:05
Base automatically changed from bxdf_fixes_cook_torrance to master November 3, 2025 13:24
@devshgraphicsprogramming
Copy link
Member

In this PR also resolve all left over comments from #930

static scalar_type __getScaledReflectance(NBL_CONST_REF_ARG(fresnel_type) orientedFresnel, NBL_CONST_REF_ARG(Interaction) interaction, scalar_type clampedVdotH)
{
spectral_type throughputWeights = interaction.getLuminosityContributionHint();
return hlsl::dot<spectral_type>(impl::__implicit_promote<spectral_type, typename fresnel_type::vector_type>::__call(orientedFresnel(clampedVdotH)), throughputWeights);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there shouldn't be an impl::__implicit_promote here at all, the spectral_type and fresnel_type::vector_type should match 100%

Comment on lines +342 to +343
dmq.microfacetMeasure = scalar_type(0.0);
dmq.projectedLightMeasure = scalar_type(0.0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both should be set to bit_cast<scale_type>(numeric_limits<scale_type>::inf) not 0s

Comment on lines +282 to +283
dmq.microfacetMeasure = scalar_type(0.0);
dmq.projectedLightMeasure = scalar_type(0.0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both should be set to bit_cast<scale_type>(numeric_limits<scale_type>::inf) not 0s

Comment on lines 400 to 404
// TODO: will probably merge with __call at some point
static void __polarized(const T orientedEta, const T orientedEtak, const T cosTheta, NBL_REF_ARG(T) Rp, NBL_REF_ARG(T) Rs)
static void __polarized(const T orientedEta, const T etaLen2, const T clampedCosTheta, NBL_REF_ARG(T) Rp, NBL_REF_ARG(T) Rs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool but this method/function should not be part of Conductor or Dielectric class, can make it free floating in fresnel namespace if you want

Also flesh out future optimizations for faster angle adding
vector_type R12p, R23p, R12s, R23s;
const vector_type scale = scalar_type(1.0)/eta12;
const vector_type cosTheta2_2 = hlsl::promote<vector_type>(1.0) - hlsl::promote<vector_type>(1-cosTheta_1*cosTheta_1) * scale * scale;
const vector_type cosTheta2_2 = hlsl::promote<vector_type>(1.0) - hlsl::promote<vector_type>(1.0-cosTheta_1*cosTheta_1) * scale * scale;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this 1.0 should be wrapped in scalar_type(1.0) before - with cos theta

you can declare a const scalar_type unity = 1.0; somwhere in the function to save yourself a headache


// Optical Path Difference
const vector_type D = hlsl::promote<vector_type>(2.0 * Dinc) * thinFilmIor * cosTheta_2;
const vector_type D = hlsl::promote<vector_type>(2.0 * params.getDinc()) * params.getThinFilmIor() * cosTheta_2;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hlsl::promote<vector_type>(2.0 * params.getDinc()) * params.getThinFilmIor() is a single vector which could be precomputed instead of getThinFilmIor()

Comment on lines 575 to 579
R12s = hlsl::mix(R12s, hlsl::promote<vector_type>(1.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));
R12p = hlsl::mix(R12p, hlsl::promote<vector_type>(1.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));

R23s = hlsl::mix(R23s, hlsl::promote<vector_type>(0.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));
R23p = hlsl::mix(R23p, hlsl::promote<vector_type>(0.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do const vector<bool,> tir = cosTheta2_2 <= hlsl::promote<vector_type>(0.0);

btw since you compute it as cosTheta_2 = hlsl::sqrt(hlsl::max(cosTheta2_2, hlsl::promote<vector_type>(0.0))); you can actually compute this condition as cosTheta2_2<=0.0

which in turns is hlsl::promote<vector_type>(1.0-cosTheta_1*cosTheta_1) * scale * scale >= 1.0

and in turn is hlsl::promote<>(1.0-cosTheta_1*cosTheta_1) >= eta12

So you can know the TIR waaay in advance

Comment on lines 637 to 656
template<typename T, bool SupportsTransmission NBL_PRIMARY_REQUIRES(concepts::FloatingPointLikeVectorial<T>)
struct iridescent_base
{
using scalar_type = typename vector_traits<T>::scalar_type;
using vector_type = T;

scalar_type getDinc() NBL_CONST_MEMBER_FUNC { return Dinc; }
vector_type getThinFilmIor() NBL_CONST_MEMBER_FUNC { return thinFilmIor; }
vector_type getEta12() NBL_CONST_MEMBER_FUNC { return eta12; }
vector_type getEta23() NBL_CONST_MEMBER_FUNC { return eta23; }
vector_type getEtak23() NBL_CONST_MEMBER_FUNC
{
NBL_IF_CONSTEXPR(SupportsTransmission)
return hlsl::promote<vector_type>(0.0);
else
return etak23;
}

scalar_type Dinc; // thickness of thin film in nanometers, rec. 100-25000nm
vector_type thinFilmIor;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still you are storking etak23 for dielectric iridescent.

don't take SupportsTransmission have etak23 and getEtak23() in your iridescent_base, define them in your Iridescent specializations and actually make them inherit instead of compose

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dinc and thinFilmIoR can be combined into a single member and getter

if you want more semantically clear initialization make creation parameter structs for Iridescent::create

Comment on lines 660 to 669
static this_t create(scalar_type Dinc, vector_type ior1, vector_type ior2, vector_type ior3, vector_type iork3)
{
this_t retval;
retval.helper.Dinc = Dinc;
retval.helper.thinFilmIor = ior2;
retval.helper.eta12 = ior2/ior1;
retval.helper.eta23 = ior3/ior2;
retval.helper.etak23 = iork3/ior2;
return retval;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where's our create from a creation parameters struct ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 574 to 583
// Check for total internal reflection
R12s = hlsl::mix(R12s, hlsl::promote<vector_type>(1.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));
R12p = hlsl::mix(R12p, hlsl::promote<vector_type>(1.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));

R23s = hlsl::mix(R23s, hlsl::promote<vector_type>(0.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));
R23p = hlsl::mix(R23p, hlsl::promote<vector_type>(0.0), cosTheta2_2 <= hlsl::promote<vector_type>(0.0));

// Compute the transmission coefficients
vector_type T121p = hlsl::promote<vector_type>(1.0) - R12p;
vector_type T121s = hlsl::promote<vector_type>(1.0) - R12s;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually it would make sense to compute a vector<bool,> tir then do if (all(tir)) path that skips a lot of the calculations (since T121p, T121s, R23s, R23p and cosTheta2 are all zero then)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also it would make sense to have a notTIR instead of tir boolean (and if (!any(notTIR)) )

because you can make a const vector_type killFactor = vector_type(notTIR); // 0 when TIR, 1 otherwise

and then you can compute R23p, R23s, T121p and T121s as originalMixLHS*killFactor

then obviously you compute R12 from 1.0-T121

Comment on lines 572 to 561
const vector_type cosTheta2_2 = hlsl::promote<vector_type>(1.0) - hlsl::promote<vector_type>(1-cosTheta_1*cosTheta_1) * scale * scale;
const vector_type cosTheta2_2 = hlsl::promote<vector_type>(1.0) - hlsl::promote<vector_type>(1.0-cosTheta_1*cosTheta_1) * scale * scale;

cosTheta_2 = hlsl::sqrt(cosTheta2_2);
cosTheta_2 = hlsl::sqrt(hlsl::max(cosTheta2_2, hlsl::promote<vector_type>(0.0)));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a little code-style correctness note, after you clamp cosTheta_2 to not have imaginary numbers due to sqrt you loose the property that cosTheta2_2 == cosTheta_2*cosTheta_2 so you should "hide" cosTheta_2_2 in its own {} scope so its not accessible after the cosTheta_2 assignment

template<typename Params>
static T __call(NBL_CONST_REF_ARG(Params) params, const scalar_type clampedCosTheta)
{
const vector_type wavelengths = vector_type(colorspace::scRGB::wavelength_R, colorspace::scRGB::wavelength_G, colorspace::scRGB::wavelength_B);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suppy colorspace from iridescent_base last template param (you can default to scSRGB)

Comment on lines +394 to +395
quo = hlsl::mix(reflectance / scaled_reflectance,
(hlsl::promote<spectral_type>(1.0) - reflectance) / (scalar_type(1.0) - scaled_reflectance), cache.isTransmission()) * G2_over_G1;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #918 (comment)

you can simplify thismix to mix(reflectance,hlsl::promote<fresnel_type::vector_type>(1.0)-reflectance,cache.isTransmission())/scaled_reflectance

@devshgraphicsprogramming devshgraphicsprogramming merged commit 08ad78a into master Nov 12, 2025
19 of 20 checks passed
@devshgraphicsprogramming devshgraphicsprogramming deleted the iridescence_bxdf branch November 12, 2025 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants