diff --git a/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl b/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl index fcf510b21..68fe8b633 100644 --- a/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl +++ b/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl @@ -8,14 +8,14 @@ using namespace nbl::hlsl; +using spectral_t = vector; using ray_dir_info_t = bxdf::ray_dir_info::SBasic; -using iso_interaction = bxdf::surface_interactions::SIsotropic; +using iso_interaction = bxdf::surface_interactions::SIsotropic; using aniso_interaction = bxdf::surface_interactions::SAnisotropic; using sample_t = bxdf::SLightSample; using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = sampling::quotient_and_pdf; -using spectral_t = vector; using iso_config_t = bxdf::SConfiguration; using aniso_config_t = bxdf::SConfiguration; @@ -32,6 +32,7 @@ void main(uint32_t3 ID : SV_DispatchThreadID) bxdf::reflection::SBeckmannAnisotropic beckmannAnisoBRDF; bxdf::reflection::SGGXIsotropic ggxIsoBRDF; bxdf::reflection::SGGXAnisotropic ggxAnisoBRDF; + bxdf::reflection::SIridescent iridBRDF; bxdf::transmission::SLambertian lambertianBSDF; bxdf::transmission::SOrenNayar orenNayarBSDF; @@ -42,6 +43,7 @@ void main(uint32_t3 ID : SV_DispatchThreadID) bxdf::transmission::SBeckmannDielectricAnisotropic beckmannAnisoBSDF; bxdf::transmission::SGGXDielectricIsotropic ggxIsoBSDF; bxdf::transmission::SGGXDielectricAnisotropic ggxAnisoBSDF; + // bxdf::transmission::SIridescent iridBSDF; // do some nonsense calculations, but call all the relevant functions @@ -76,6 +78,9 @@ void main(uint32_t3 ID : SV_DispatchThreadID) s = ggxAnisoBRDF.generate(anisointer, u.xy, cache); L += s.L.direction; + qp = iridBRDF.quotient_and_pdf(s, anisointer, cache); + L -= qp.quotient; + qp = ggxAnisoBRDF.quotient_and_pdf(s, anisointer, cache); L -= qp.quotient; diff --git a/66_HLSLBxDFTests/app_resources/test_components.hlsl b/66_HLSLBxDFTests/app_resources/test_components.hlsl index 9631db05d..cd2aa5cb6 100644 --- a/66_HLSLBxDFTests/app_resources/test_components.hlsl +++ b/66_HLSLBxDFTests/app_resources/test_components.hlsl @@ -90,7 +90,7 @@ struct TestNDF : TestBxDF NBL_IF_CONSTEXPR(aniso) { dg1_query_type dq = base_t::bxdf.ndf.template createDG1Query(base_t::anisointer, cache); - fresnel_type _f = bxdf::impl::getOrientedFresnel::__call(base_t::bxdf.fresnel, base_t::anisointer.getNdotV()); + fresnel_type _f = base_t::bxdf_t::getOrientedFresnel(base_t::bxdf.fresnel, base_t::anisointer.getNdotV()); quant_query_type qq = bxdf::impl::quant_query_helper::template __call(base_t::bxdf.ndf, _f, cache); quant_type DG1 = base_t::bxdf.ndf.template DG1(dq, qq, s, base_t::anisointer); dg1 = DG1.microfacetMeasure * hlsl::abs(cache.getVdotH() / base_t::anisointer.getNdotV()); @@ -101,7 +101,7 @@ struct TestNDF : TestBxDF else { dg1_query_type dq = base_t::bxdf.ndf.template createDG1Query(base_t::isointer, isocache); - fresnel_type _f = bxdf::impl::getOrientedFresnel::__call(base_t::bxdf.fresnel, base_t::isointer.getNdotV()); + fresnel_type _f = base_t::bxdf_t::getOrientedFresnel(base_t::bxdf.fresnel, base_t::isointer.getNdotV()); quant_query_type qq = bxdf::impl::quant_query_helper::template __call(base_t::bxdf.ndf, _f, isocache); quant_type DG1 = base_t::bxdf.ndf.template DG1(dq, qq, s, base_t::isointer); dg1 = DG1.microfacetMeasure * hlsl::abs(isocache.getVdotH() / base_t::isointer.getNdotV()); diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 9011aa2e5..650449df5 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -69,7 +69,6 @@ struct TestJacobian : TestBxDF if (!(s.isValid() && sx.isValid() && sy.isValid())) return BET_INVALID; - // TODO: add checks with need clamp trait if (traits_t::type == bxdf::BT_BRDF) { if (s.getNdotL() <= bit_cast(numeric_limits::min)) @@ -245,7 +244,6 @@ struct TestReciprocity : TestBxDF if (!s.isValid()) return BET_INVALID; - // TODO: add checks with need clamp trait if (bxdf::traits::type == bxdf::BT_BRDF) { if (s.getNdotL() <= bit_cast(numeric_limits::min)) @@ -264,6 +262,7 @@ struct TestReciprocity : TestBxDF rec_s = sample_t::createFromTangentSpace(rec_localL, anisointer.getFromTangentSpace()); rec_isointer = iso_interaction_t::create(rec_V, base_t::rc.N); + rec_isointer.luminosityContributionHint = isointer.luminosityContributionHint; rec_anisointer = aniso_interaction_t::create(rec_isointer, base_t::rc.T, base_t::rc.B); rec_cache = cache; rec_cache.iso_cache.VdotH = cache.iso_cache.getLdotH(); diff --git a/66_HLSLBxDFTests/app_resources/tests_common.hlsl b/66_HLSLBxDFTests/app_resources/tests_common.hlsl index c0a8d9614..9de407e39 100644 --- a/66_HLSLBxDFTests/app_resources/tests_common.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests_common.hlsl @@ -46,14 +46,14 @@ namespace nbl namespace hlsl { +using spectral_t = vector; using ray_dir_info_t = bxdf::ray_dir_info::SBasic; -using iso_interaction = bxdf::surface_interactions::SIsotropic; +using iso_interaction = bxdf::surface_interactions::SIsotropic; using aniso_interaction = bxdf::surface_interactions::SAnisotropic; using sample_t = bxdf::SLightSample; using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = sampling::quotient_and_pdf; -using spectral_t = vector; using iso_config_t = bxdf::SConfiguration; using aniso_config_t = bxdf::SConfiguration; @@ -81,6 +81,14 @@ bool checkEq(T a, T b, float32_t eps) return nbl::hlsl::all::Dimension> >(nbl::hlsl::max(_a / _b, _b / _a) <= hlsl::promote(1 + eps)); } +template<> +bool checkEq(float32_t a, float32_t b, float32_t eps) +{ + float32_t _a = hlsl::abs(a); + float32_t _b = hlsl::abs(b); + return nbl::hlsl::max(_a / _b, _b / _a) <= float32_t(1 + eps); +} + template bool checkLt(T a, T b) { @@ -110,12 +118,9 @@ struct SBxDFTestResources retval.u = ConvertToFloat01::__call(rng_vec3()); retval.u.x = hlsl::clamp(retval.u.x, retval.eps, 1.f-retval.eps); retval.u.y = hlsl::clamp(retval.u.y, retval.eps, 1.f-retval.eps); - // retval.u.z = 0.0; retval.V.direction = nbl::hlsl::normalize(sampling::UniformSphere::generate(ConvertToFloat01::__call(rng_vec2()))); retval.N = nbl::hlsl::normalize(sampling::UniformSphere::generate(ConvertToFloat01::__call(rng_vec2()))); - // if (hlsl::dot(retval.N, retval.V.direction) < 0) - // retval.V.direction = -retval.V.direction; float32_t3 tangent, bitangent; math::frisvad(retval.N, tangent, bitangent); @@ -131,6 +136,9 @@ struct SBxDFTestResources retval.alpha.y = ConvertToFloat01::__call(retval.rng()); retval.eta = ConvertToFloat01::__call(rng_vec2()) * hlsl::promote(1.5) + hlsl::promote(1.1); // range [1.1,2.6], also only do eta = eta/1.0 (air) retval.luma_coeff = float32_t3(0.2126, 0.7152, 0.0722); // luma coefficients for Rec. 709 + + retval.Dinc = ConvertToFloat01::__call(retval.rng()) * 2400.0f + 100.0f; + retval.etaThinFilm = ConvertToFloat01::__call(retval.rng()) * 0.5 + 1.1f; // range [1.1,1.6] return retval; } @@ -147,6 +155,10 @@ struct SBxDFTestResources float32_t2 alpha; float32_t2 eta; // (eta, etak) float32_t3 luma_coeff; + + // thin film stuff; + float Dinc; // in nm [100, 2500] + float etaThinFilm; }; struct STestInitParams @@ -184,6 +196,7 @@ struct TestBase rc = SBxDFTestResources::create(seed); isointer = iso_interaction::create(rc.V, rc.N); + isointer.luminosityContributionHint = rc.luma_coeff; anisointer = aniso_interaction::create(isointer, rc.T, rc.B); } @@ -315,6 +328,28 @@ struct TestBxDF> : } }; +template<> +struct TestBxDF> : TestBxDFBase> +{ + using base_t = TestBxDFBase>; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf.ndf = base_t::bxdf_t::ndf_type::create(_rc.alpha.x); + using fresnel_params_t = base_t::bxdf_t::fresnel_type::creation_params_type; + fresnel_params_t params; + params.Dinc = _rc.Dinc; + params.ior1 = hlsl::promote(1.0); + params.ior2 = hlsl::promote(_rc.etaThinFilm); + params.ior3 = hlsl::promote(_rc.eta.x); + params.iork3 = hlsl::promote(_rc.eta.y); + base_t::bxdf.fresnel = base_t::bxdf_t::fresnel_type::create(params); +#ifndef __HLSL_VERSION + base_t::name = "Iridescent BRDF"; +#endif + } +}; + template<> struct TestBxDF> : TestBxDFBase> { @@ -354,7 +389,6 @@ struct TestBxDF> : TestB { using spectral_type = typename base_t::bxdf_t::spectral_type; base_t::bxdf.fresnel = bxdf::fresnel::Dielectric::create(bxdf::fresnel::OrientedEtas::create(base_t::isointer.getNdotV(bxdf::BxDFClampMode::BCM_ABS), hlsl::promote(_rc.eta.x))); - base_t::bxdf.luminosityContributionHint = _rc.luma_coeff; #ifndef __HLSL_VERSION base_t::name = "Thin smooth dielectric BSDF"; #endif @@ -438,37 +472,62 @@ struct TestBxDF> : TestBxD } }; +template +struct TestBxDF> : TestBxDFBase> +{ + using base_t = TestBxDFBase>; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf.ndf = base_t::bxdf_t::ndf_type::create(_rc.alpha.x); + using fresnel_params_t = base_t::bxdf_t::fresnel_type::creation_params_type; + fresnel_params_t params; + params.Dinc = _rc.Dinc; + params.ior1 = hlsl::promote(1.0); + params.ior2 = hlsl::promote(_rc.etaThinFilm); + params.ior3 = hlsl::promote(_rc.eta.x); + base_t::bxdf.fresnel = base_t::bxdf_t::fresnel_type::create(params); +#ifndef __HLSL_VERSION + base_t::name = "Iridescent BSDF"; +#endif + } +}; + namespace reciprocity_test_impl { -template) +template && concepts::FloatingPointLikeVectorial) struct SIsotropic { + using this_t = SIsotropic; using ray_dir_info_type = RayDirInfo; using scalar_type = typename RayDirInfo::scalar_type; using vector3_type = typename RayDirInfo::vector3_type; + using spectral_type = Spectrum; // WARNING: Changed since GLSL, now arguments need to be normalized! - static SIsotropic create(NBL_CONST_REF_ARG(RayDirInfo) normalizedV, const vector3_type normalizedN) + static this_t create(NBL_CONST_REF_ARG(RayDirInfo) normalizedV, const vector3_type normalizedN) { - SIsotropic retval; + this_t retval; retval.V = normalizedV; retval.N = normalizedN; retval.NdotV = nbl::hlsl::dot(retval.N, retval.V.getDirection()); retval.NdotV2 = retval.NdotV * retval.NdotV; + retval.luminosityContributionHint = hlsl::promote(1.0); return retval; } template) - static SIsotropic copy(NBL_CONST_REF_ARG(I) other) + static this_t copy(NBL_CONST_REF_ARG(I) other) { - SIsotropic retval; + this_t retval; retval.V = other.getV(); retval.N = other.getN(); retval.NdotV = other.getNdotV(); retval.NdotV2 = other.getNdotV2(); retval.pathOrigin = bxdf::PathOrigin::PO_SENSOR; + retval.luminosityContributionHint = other.luminosityContributionHint; return retval; } @@ -481,12 +540,14 @@ struct SIsotropic scalar_type getNdotV2() NBL_CONST_MEMBER_FUNC { return NdotV2; } bxdf::PathOrigin getPathOrigin() NBL_CONST_MEMBER_FUNC { return pathOrigin; } + spectral_type getLuminosityContributionHint() NBL_CONST_MEMBER_FUNC { return luminosityContributionHint; } RayDirInfo V; vector3_type N; scalar_type NdotV; scalar_type NdotV2; bxdf::PathOrigin pathOrigin; + spectral_type luminosityContributionHint; }; template) @@ -498,6 +559,7 @@ struct SAnisotropic using scalar_type = typename ray_dir_info_type::scalar_type; using vector3_type = typename ray_dir_info_type::vector3_type; using matrix3x3_type = matrix; + using spectral_type = typename isotropic_interaction_type::spectral_type; // WARNING: Changed since GLSL, now arguments need to be normalized! static this_t create( @@ -551,6 +613,7 @@ struct SAnisotropic scalar_type getNdotV(bxdf::BxDFClampMode _clamp = bxdf::BxDFClampMode::BCM_NONE) NBL_CONST_MEMBER_FUNC { return isotropic.getNdotV(_clamp); } scalar_type getNdotV2() NBL_CONST_MEMBER_FUNC { return isotropic.getNdotV2(); } bxdf::PathOrigin getPathOrigin() NBL_CONST_MEMBER_FUNC { return isotropic.getPathOrigin(); } + spectral_type getLuminosityContributionHint() NBL_CONST_MEMBER_FUNC { return isotropic.getLuminosityContributionHint(); } vector3_type getT() NBL_CONST_MEMBER_FUNC { return T; } vector3_type getB() NBL_CONST_MEMBER_FUNC { return B; } @@ -599,7 +662,7 @@ struct CustomIsoMicrofacetConfiguration; +using rectest_iso_interaction = reciprocity_test_impl::SIsotropic; using rectest_aniso_interaction = reciprocity_test_impl::SAnisotropic; using rectest_iso_microfacet_config_t = reciprocity_test_impl::CustomIsoMicrofacetConfiguration; using rectest_aniso_microfacet_config_t = bxdf::SMicrofacetConfiguration; diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index a65b443c9..876965875 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -193,6 +193,7 @@ int main(int argc, char** argv) TestJacobian, true>::run(initparams, cb); TestJacobian, false>::run(initparams, cb); TestJacobian,true>::run(initparams, cb); + TestJacobian, false>::run(initparams, cb); TestJacobian>::run(initparams, cb); TestJacobian>::run(initparams, cb); @@ -203,6 +204,7 @@ int main(int argc, char** argv) TestJacobian, true>::run(initparams, cb); TestJacobian, false>::run(initparams, cb); TestJacobian,true>::run(initparams, cb); + TestJacobian, false>::run(initparams, cb); FOR_EACH_END @@ -211,7 +213,7 @@ int main(int argc, char** argv) auto rReciprocity = std::ranges::views::iota(0u, runs); FOR_EACH_BEGIN(rReciprocity) STestInitParams initparams{ .logInfo = logInfo }; - initparams.state = 3; + initparams.state = i; initparams.verbose = testconfigs["TestReciprocity"]["verbose"]; TestReciprocity>::run(initparams, cb); @@ -221,16 +223,18 @@ int main(int argc, char** argv) TestReciprocity, true>::run(initparams, cb); TestReciprocity, false>::run(initparams, cb); TestReciprocity, true>::run(initparams, cb); + TestReciprocity, false>::run(initparams, cb); TestReciprocity>::run(initparams, cb); TestReciprocity>::run(initparams, cb); - TestReciprocity>::run(initparams, cb); + TestReciprocity>::run(initparams, cb); TestReciprocity>::run(initparams, cb); TestReciprocity>::run(initparams, cb); TestReciprocity, false>::run(initparams, cb); TestReciprocity, true>::run(initparams, cb); TestReciprocity, false>::run(initparams, cb); TestReciprocity, true>::run(initparams, cb); + //TestReciprocity, false>::run(initparams, cb); // viewing angle changes result? FOR_EACH_END @@ -249,6 +253,7 @@ int main(int argc, char** argv) TestBucket, true>::run(initparams, cb); TestBucket, false>::run(initparams, cb); TestBucket, true>::run(initparams, cb); + TestBucket, false>::run(initparams, cb); TestBucket>::run(initparams, cb); TestBucket>::run(initparams, cb); @@ -256,6 +261,7 @@ int main(int argc, char** argv) TestBucket, true>::run(initparams, cb); TestBucket, false>::run(initparams, cb); TestBucket, true>::run(initparams, cb); + TestBucket, false>::run(initparams, cb); FOR_EACH_END @@ -276,6 +282,7 @@ int main(int argc, char** argv) TestChi2, true>::run(initparams, cb); TestChi2, false>::run(initparams, cb); TestChi2, true>::run(initparams, cb); + TestChi2, false>::run(initparams, cb); TestChi2>::run(initparams, cb); TestChi2>::run(initparams, cb); @@ -283,6 +290,7 @@ int main(int argc, char** argv) TestChi2, true>::run(initparams, cb); TestChi2, false>::run(initparams, cb); TestChi2, true>::run(initparams, cb); + TestChi2, false>::run(initparams, cb); FOR_EACH_END #if 0 @@ -330,22 +338,35 @@ int main(int argc, char** argv) // test arccos angle sums { Xoroshiro64Star rng = Xoroshiro64Star::construct(uint32_t2(4, 2)); + math::sincos_accumulator angle_adder; + + auto Sin = [&](const float cosA) -> float + { + return nbl::hlsl::sqrt(1.f - cosA * cosA); + }; + for (uint32_t i = 0; i < 10; i++) { - const float a = rng() * numbers::pi; - const float b = rng() * numbers::pi; - const float c = rng() * numbers::pi; - const float d = rng() * numbers::pi; + const float a = ConvertToFloat01::__call(rng()) * 2.f - 1.f; + const float b = ConvertToFloat01::__call(rng()) * 2.f - 1.f; + const float c = ConvertToFloat01::__call(rng()) * 2.f - 1.f; + const float d = ConvertToFloat01::__call(rng()) * 2.f - 1.f; const float exAB = acos(a) + acos(b); - float res = math::getSumofArccosAB(a, b); - if (res != exAB) - fprintf(stderr, "[ERROR] math::getSumofArccosAB failed! expected %f, got %f\n", exAB, res); + angle_adder = math::sincos_accumulator::create(a, Sin(a)); + angle_adder.addCosine(b, Sin(b)); + float res = angle_adder.getSumofArccos(); + if (!checkEq(res, exAB, 1e-3)) + fprintf(stderr, "[ERROR] angle adding (2 angles) failed! expected %f, got %f\n", exAB, res); const float exABCD = exAB + acos(c) + acos(d); - res = math::getSumofArccosABCD(a, b, c, d); - if (res != exABCD) - fprintf(stderr, "[ERROR] math::getSumofArccosABCD failed! expected %f, got %f\n", exABCD, res); + angle_adder = math::sincos_accumulator::create(a, Sin(a)); + angle_adder.addCosine(b, Sin(b)); + angle_adder.addCosine(c, Sin(c)); + angle_adder.addCosine(d, Sin(d)); + res = angle_adder.getSumofArccos(); + if (!checkEq(res, exABCD, 1e-3)) + fprintf(stderr, "[ERROR] angle adding (4 angles) failed! expected %f, got %f\n", exABCD, res); } }