diff --git a/31_HLSLPathTracer/app_resources/hlsl/compute_render_scene_impl.hlsl b/31_HLSLPathTracer/app_resources/hlsl/compute_render_scene_impl.hlsl index 8706a8917..88d6b5000 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/compute_render_scene_impl.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/compute_render_scene_impl.hlsl @@ -53,10 +53,9 @@ RenderPushConstants getRenderPushConstants() } template -void tracePixel(int32_t2 coords) +void tracePixel(NBL_REF_ARG(typename SVariantTypes::pathtracer_type) pathtracer, int32_t2 coords) { const RenderPushConstants renderPushConstants = getRenderPushConstants(); - using variant_types = SVariantTypes; uint32_t width, height, imageArraySize; ::outImage.GetDimensions(width, height, imageArraySize); @@ -72,8 +71,6 @@ void tracePixel(int32_t2 coords) return; } - typename variant_types::pathtracer_type pathtracer; - uint2 scrambleDim; ::scramblebuf.GetDimensions(scrambleDim.x, scrambleDim.y); const float32_t2 pixOffsetParam = float32_t2(1.0, 1.0) / float32_t2(scrambleDim); @@ -86,24 +83,15 @@ void tracePixel(int32_t2 coords) NDC.z = 1.0; } - scene_type scene; - scene.updateLight(renderPushConstants.getLightMatrix()); - + using variant_types = SVariantTypes; typename variant_types::raygen_type rayGen; rayGen.pixOffsetParam = pixOffsetParam; rayGen.camPos = camPos; rayGen.NDC = NDC; rayGen.invMVP = renderPushConstants.invMVP; - pathtracer.scene = scene; - pathtracer.randGen.pSampleBuffer = renderPushConstants.pSampleSequence; + const uint32_t2 scrambleCoord = uint32_t2(coords.x & 511, coords.y & 511); pathtracer.randGen.rng = Xoroshiro64Star::construct(scramblebuf[coords].rg); - pathtracer.randGen.sequenceSamplesLog2 = renderPushConstants.sequenceSampleCountLog2; - pathtracer.nee.lights = lights; - pathtracer.materialSystem.bxdfs = bxdfs; - pathtracer.bxdfPdfThreshold = 0.0001; - pathtracer.lumaContributionThreshold = hlsl::dot(colorspace::scRGBtoXYZ[1], colorspace::eotf::sRGB(hlsl::promote(1.0 / 255.0))); - pathtracer.spectralTypeToLumaCoeffs = colorspace::scRGBtoXYZ[1]; #if PATH_TRACER_USE_RWMC accumulator_type accumulator = accumulator_type::create(::pc.splattingParameters); @@ -133,7 +121,23 @@ void runLinear(uint32_t3 threadID) { uint32_t width, height, imageArraySize; ::outImage.GetDimensions(width, height, imageArraySize); - tracePixel(int32_t2(threadID.x % width, threadID.x / width)); + + const RenderPushConstants renderPushConstants = getRenderPushConstants(); + scene_type scene; + scene.updateLight(renderPushConstants.getLightMatrix()); + + using variant_types = SVariantTypes; + typename variant_types::pathtracer_type pathtracer; + pathtracer.scene = scene; + pathtracer.randGen.sequenceSamplesLog2 = renderPushConstants.sequenceSampleCountLog2; + pathtracer.randGen.pSampleBuffer = renderPushConstants.pSampleSequence; + pathtracer.nee.lights = lights; + pathtracer.materialSystem.bxdfs = bxdfs; + pathtracer.bxdfPdfThreshold = 0.0001; + pathtracer.lumaContributionThreshold = hlsl::dot(colorspace::scRGBtoXYZ[1], colorspace::eotf::sRGB(hlsl::promote(1.0 / 255.0))); + pathtracer.spectralTypeToLumaCoeffs = colorspace::scRGBtoXYZ[1]; + + tracePixel(pathtracer, int32_t2(threadID.x % width, threadID.x / width)); } #endif @@ -146,6 +150,21 @@ void runPersistent() const uint32_t numWorkgroupsX = width / RenderWorkgroupSizeSqrt; const uint32_t numWorkgroupsY = height / RenderWorkgroupSizeSqrt; + const RenderPushConstants renderPushConstants = getRenderPushConstants(); + scene_type scene; + scene.updateLight(renderPushConstants.getLightMatrix()); + + using variant_types = SVariantTypes; + typename variant_types::pathtracer_type pathtracer; + pathtracer.scene = scene; + pathtracer.randGen.sequenceSamplesLog2 = renderPushConstants.sequenceSampleCountLog2; + pathtracer.randGen.pSampleBuffer = renderPushConstants.pSampleSequence; + pathtracer.nee.lights = lights; + pathtracer.materialSystem.bxdfs = bxdfs; + pathtracer.bxdfPdfThreshold = 0.0001; + pathtracer.lumaContributionThreshold = hlsl::dot(colorspace::scRGBtoXYZ[1], colorspace::eotf::sRGB(hlsl::promote(1.0 / 255.0))); + pathtracer.spectralTypeToLumaCoeffs = colorspace::scRGBtoXYZ[1]; + [loop] for (uint32_t wgBase = glsl::gl_WorkGroupID().x; wgBase < numWorkgroupsX * numWorkgroupsY; wgBase += glsl::gl_NumWorkGroups().x) { @@ -153,7 +172,7 @@ void runPersistent() morton::code mc; mc.value = glsl::gl_LocalInvocationIndex().x; const int32_t2 localCoords = _static_cast(mc); - tracePixel(wgCoords * int32_t2(RenderWorkgroupSizeSqrt, RenderWorkgroupSizeSqrt) + localCoords); + tracePixel(pathtracer, wgCoords * int32_t2(RenderWorkgroupSizeSqrt, RenderWorkgroupSizeSqrt) + localCoords); } } #endif diff --git a/31_HLSLPathTracer/app_resources/hlsl/example_common.hlsl b/31_HLSLPathTracer/app_resources/hlsl/example_common.hlsl index dc962bce2..59b049861 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/example_common.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/example_common.hlsl @@ -86,6 +86,7 @@ struct Ray // mutable scalar_type intersectionT; + uint16_t depth; payload_type payload; using spectral_type = typename payload_type::spectral_type; @@ -133,6 +134,7 @@ struct Ray void setT(scalar_type t) { intersectionT = t; } scalar_type getT() NBL_CONST_MEMBER_FUNC { return intersectionT; } + void setDepth(uint16_t d) { depth = d; } spectral_type getPayloadThroughput() NBL_CONST_MEMBER_FUNC { return payload.throughput; } }; @@ -154,6 +156,7 @@ struct Ray // mutable scalar_type intersectionT; + uint16_t depth; payload_type payload; using spectral_type = typename payload_type::spectral_type; @@ -202,6 +205,7 @@ struct Ray void setT(scalar_type t) { intersectionT = t; } scalar_type getT() NBL_CONST_MEMBER_FUNC { return intersectionT; } + void setDepth(uint16_t d) { depth = d; } vector3_type getPayloadThroughput() NBL_CONST_MEMBER_FUNC { return payload.throughput; } }; @@ -234,7 +238,7 @@ struct Light template struct Tolerance { - NBL_CONSTEXPR_STATIC_INLINE T INTERSECTION_ERROR_BOUND_LOG2 = -8.0; + NBL_CONSTEXPR_STATIC_INLINE T INTERSECTION_ERROR_BOUND_LOG2 = -12.0; static T __common(uint16_t depth) { @@ -700,7 +704,8 @@ struct PTIsoConfiguration; using sample_type = LS; using spectral_type = Spectrum; - using quotient_pdf_type = sampling::quotient_and_pdf; + using quotient_weight_type = sampling::quotient_and_pdf; + using value_weight_type = sampling::value_and_weight; }; template diff --git a/31_HLSLPathTracer/app_resources/hlsl/material_system.hlsl b/31_HLSLPathTracer/app_resources/hlsl/material_system.hlsl index 9798ad8e8..616fdec59 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/material_system.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/material_system.hlsl @@ -21,7 +21,8 @@ struct MaterialSystem using measure_type = typename DiffuseBxDF::spectral_type; using sample_type = typename DiffuseBxDF::sample_type; using ray_dir_info_type = typename sample_type::ray_dir_info_type; - using quotient_pdf_type = typename DiffuseBxDF::quotient_pdf_type; + using quotient_weight_type = typename DiffuseBxDF::quotient_weight_type; + using value_weight_type = typename DiffuseBxDF::value_weight_type; using anisotropic_interaction_type = typename DiffuseBxDF::anisotropic_interaction_type; using isotropic_interaction_type = typename anisotropic_interaction_type::isotropic_interaction_type; using anisocache_type = typename ConductorBxDF::anisocache_type; @@ -133,7 +134,7 @@ struct MaterialSystem } } - measure_type eval(material_id_type matID, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + value_weight_type evalAndWeight(material_id_type matID, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) { cache_type _cache = getCacheFromSampleInteraction(matID, _sample, interaction); MaterialType matType = (MaterialType)bxdfs[matID.id].materialType; @@ -141,26 +142,28 @@ struct MaterialSystem { case MaterialType::DIFFUSE: { - return bxdfs[matID.id].albedo * _cache.diffuseBxDF.eval(_sample, interaction.isotropic); + value_weight_type ret = _cache.diffuseBxDF.evalAndWeight(_sample, interaction.isotropic); + ret._value *= bxdfs[matID.id].albedo; + return ret; } case MaterialType::CONDUCTOR: { - return _cache.conductorBxDF.eval(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.conductorBxDF.evalAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::DIELECTRIC: { - return _cache.dielectricBxDF.eval(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.dielectricBxDF.evalAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::IRIDESCENT_CONDUCTOR: { - return _cache.iridescentConductorBxDF.eval(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.iridescentConductorBxDF.evalAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::IRIDESCENT_DIELECTRIC: { - return _cache.iridescentDielectricBxDF.eval(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.iridescentDielectricBxDF.evalAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } default: - return hlsl::promote(0.0); + return value_weight_type::create(0.0, 0.0); } } @@ -172,7 +175,8 @@ struct MaterialSystem { case MaterialType::DIFFUSE: { - return _cache.diffuseBxDF.generate(interaction, u.xy); + typename diffuse_op_type::isocache_type dummycache; + return _cache.diffuseBxDF.generate(interaction, u.xy, dummycache); } case MaterialType::CONDUCTOR: { @@ -230,7 +234,7 @@ struct MaterialSystem } } - quotient_pdf_type quotient_and_pdf(material_id_type matID, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_REF_ARG(cache_type) _cache) + quotient_weight_type quotientAndWeight(material_id_type matID, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_REF_ARG(cache_type) _cache) { const float minimumProjVectorLen = 0.00000001; // TODO: still need this check? if (interaction.getNdotV(bxdf::BxDFClampMode::BCM_ABS) > minimumProjVectorLen && _sample.getNdotL(bxdf::BxDFClampMode::BCM_ABS) > minimumProjVectorLen) @@ -240,31 +244,32 @@ struct MaterialSystem { case MaterialType::DIFFUSE: { - quotient_pdf_type ret = _cache.diffuseBxDF.quotient_and_pdf(_sample, interaction.isotropic); + typename diffuse_op_type::isocache_type dummycache; + quotient_weight_type ret = _cache.diffuseBxDF.quotientAndWeight(_sample, interaction.isotropic, dummycache); ret._quotient *= bxdfs[matID.id].albedo; return ret; } case MaterialType::CONDUCTOR: { - return _cache.conductorBxDF.quotient_and_pdf(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.conductorBxDF.quotientAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::DIELECTRIC: { - return _cache.dielectricBxDF.quotient_and_pdf(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.dielectricBxDF.quotientAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::IRIDESCENT_CONDUCTOR: { - return _cache.iridescentConductorBxDF.quotient_and_pdf(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.iridescentConductorBxDF.quotientAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } case MaterialType::IRIDESCENT_DIELECTRIC: { - return _cache.iridescentDielectricBxDF.quotient_and_pdf(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); + return _cache.iridescentDielectricBxDF.quotientAndWeight(_sample, interaction.isotropic, _cache.aniso_cache.iso_cache); } default: break; } } - return quotient_pdf_type::create(hlsl::promote(0.0), 0.0); + return quotient_weight_type::create(0.0, 0.0); } bool hasEmission(material_id_type matID) diff --git a/31_HLSLPathTracer/app_resources/hlsl/next_event_estimator.hlsl b/31_HLSLPathTracer/app_resources/hlsl/next_event_estimator.hlsl index c8bee786c..227af9e24 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/next_event_estimator.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/next_event_estimator.hlsl @@ -29,7 +29,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { vector3_type Z = sphere.position - origin; const scalar_type distanceSQ = hlsl::dot(Z,Z); @@ -87,7 +87,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type edge0 = tri.vertex1 - tri.vertex0; const vector3_type edge1 = tri.vertex2 - tri.vertex0; @@ -131,7 +131,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type tri_vertices[3] = {tri.vertex0, tri.vertex1, tri.vertex2}; shapes::SphericalTriangle st = shapes::SphericalTriangle::create(tri_vertices, origin); @@ -183,7 +183,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type tri_vertices[3] = {tri.vertex0, tri.vertex1, tri.vertex2}; shapes::SphericalTriangle st = shapes::SphericalTriangle::create(tri_vertices, origin); @@ -225,7 +225,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type N = rect.getNormalTimesArea(); const vector3_type origin2origin = rect.offset - origin; @@ -275,7 +275,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type N = rect.getNormalTimesArea(); const vector3_type origin2origin = rect.offset - origin; @@ -363,7 +363,7 @@ struct ShapeSampling } template - vector3_type generate_and_pdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) + vector3_type generateAndPdf(NBL_REF_ARG(scalar_type) pdf, NBL_REF_ARG(scalar_type) newRayMaxT, NBL_CONST_REF_ARG(vector3_type) origin, NBL_CONST_REF_ARG(Aniso) interaction, NBL_CONST_REF_ARG(vector3_type) xi) { const vector3_type N = rect.getNormalTimesArea(); const vector3_type origin2origin = rect.offset - origin; @@ -411,7 +411,7 @@ struct NextEventEstimator using light_id_type = LightID; using spectral_type = typename light_type::spectral_type; using interaction_type = Aniso; - using quotient_pdf_type = sampling::quotient_and_pdf; + using quotient_weight_type = sampling::quotient_and_pdf; using sample_type = LightSample; using ray_dir_info_type = typename sample_type::ray_dir_info_type; using tolerance_method_type = Tolerance; @@ -421,17 +421,17 @@ struct NextEventEstimator struct SampleQuotientReturn { using sample_type = sample_type; - using quotient_pdf_type = quotient_pdf_type; + using quotient_weight_type = quotient_weight_type; using scalar_type = scalar_type; using object_handle_type = ObjectID; sample_type sample_; - quotient_pdf_type quotient_pdf; + quotient_weight_type quotient_weight; scalar_type newRayMaxT; object_handle_type lightObjectID; sample_type getSample() NBL_CONST_MEMBER_FUNC { return sample_; } - quotient_pdf_type getQuotientPdf() NBL_CONST_MEMBER_FUNC { return quotient_pdf; } + quotient_weight_type getQuotientWeight() NBL_CONST_MEMBER_FUNC { return quotient_weight; } scalar_type getT() NBL_CONST_MEMBER_FUNC { return newRayMaxT; } object_handle_type getLightObjectID() NBL_CONST_MEMBER_FUNC { return lightObjectID; } }; @@ -455,7 +455,7 @@ struct NextEventEstimator return scene.getRectangle(lightObjectID); } - scalar_type deferred_pdf(NBL_CONST_REF_ARG(scene_type) scene, light_id_type lightID, NBL_CONST_REF_ARG(ray_type) ray) + scalar_type deferredWeight(NBL_CONST_REF_ARG(scene_type) scene, light_id_type lightID, NBL_CONST_REF_ARG(ray_type) ray) { if (lightID.id == 0u) return scalar_type(0.0); // env light pdf=0 @@ -466,7 +466,7 @@ struct NextEventEstimator } template - sample_quotient_return_type generate_and_quotient_and_pdf(NBL_CONST_REF_ARG(scene_type) scene, NBL_CONST_REF_ARG(MaterialSystem) materialSystem, const vector3_type origin, NBL_CONST_REF_ARG(interaction_type) interaction, const vector3_type xi, uint16_t depth) + sample_quotient_return_type generateAndQuotientAndWeight(NBL_CONST_REF_ARG(scene_type) scene, NBL_CONST_REF_ARG(MaterialSystem) materialSystem, const vector3_type origin, NBL_CONST_REF_ARG(interaction_type) interaction, const vector3_type xi, NBL_CONST_REF_ARG(ray_type) ray) { // light id 0 is reserved for env light // however, we start indexing light array without env light, so index 0 is first shape light @@ -478,7 +478,7 @@ struct NextEventEstimator sample_quotient_return_type retval; scalar_type pdf, newRayMaxT; const shape_sampling_type sampling = shape_sampling_type::create(shape); - const vector3_type sampleL = sampling.template generate_and_pdf(pdf, newRayMaxT, origin, interaction, xi); + const vector3_type sampleL = sampling.template generateAndPdf(pdf, newRayMaxT, origin, interaction, xi); const vector3_type N = interaction.getN(); const scalar_type NdotL = nbl::hlsl::dot(N, sampleL); @@ -495,17 +495,17 @@ struct NextEventEstimator rayL.setDirection(sampleL); retval.sample_ = sample_type::create(rayL,interaction.getT(),interaction.getB(),NdotL); - newRayMaxT *= tolerance_method_type::getEnd(depth); + newRayMaxT *= tolerance_method_type::getEnd(ray.depth); pdf *= 1.0 / scalar_type(scene_type::SCENE_LIGHT_COUNT); const spectral_type radiance = materialSystem.getEmission(light.emissiveMatID, interaction); spectral_type quo = radiance / pdf; - retval.quotient_pdf = quotient_pdf_type::create(quo, pdf); + retval.quotient_weight = quotient_weight_type::create(quo, pdf); retval.newRayMaxT = newRayMaxT; retval.lightObjectID = light.objectID; } else { - retval.quotient_pdf = quotient_pdf_type::create(0.0, 0.0); + retval.quotient_weight = quotient_weight_type::create(0.0, 0.0); ray_dir_info_type rayL; rayL.makeInvalid(); retval.sample_ = sample_type::create(rayL,hlsl::promote(0.0)); @@ -514,14 +514,14 @@ struct NextEventEstimator return retval; } - light_id_type get_env_light_id() + light_id_type getEnvLightId() { light_id_type env_light_id; env_light_id.id = 0u; return env_light_id; } - spectral_type get_environment_radiance(NBL_CONST_REF_ARG(ray_type) ray) + spectral_type getEnvRadiance(NBL_CONST_REF_ARG(ray_type) ray) { // can also sample environment map using ray direction return vector3_type(0.15, 0.21, 0.3); diff --git a/31_HLSLPathTracer/app_resources/hlsl/scene_rectangle_light.hlsl b/31_HLSLPathTracer/app_resources/hlsl/scene_rectangle_light.hlsl index 4dd821a94..1de46021f 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/scene_rectangle_light.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/scene_rectangle_light.hlsl @@ -65,7 +65,7 @@ struct SceneRectangleLight : SceneBase vector3_type N = objectID.shapeType == PST_SPHERE ? getSphere(objectID.id).getNormal(intersection.position) : getRectangle(objectID.id).getNormalTimesArea(); N = hlsl::normalize(N); - intersection.geometricNormal = N; + intersection.geometricNormal = ieee754::flipSignIfRHSNegative(N, hlsl::promote(-hlsl::dot(N, rayIntersected.direction))); ray_dir_info_t V; V.setDirection(-rayIntersected.direction); interaction_type interaction = interaction_type::create(V, N); diff --git a/31_HLSLPathTracer/app_resources/hlsl/scene_sphere_light.hlsl b/31_HLSLPathTracer/app_resources/hlsl/scene_sphere_light.hlsl index 17ea519c6..bb767a652 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/scene_sphere_light.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/scene_sphere_light.hlsl @@ -68,7 +68,7 @@ struct SceneSphereLight : SceneBase vector3_type N = getSphere(objectID.id).getNormal(intersection.position); N = hlsl::normalize(N); - intersection.geometricNormal = N; + intersection.geometricNormal = ieee754::flipSignIfRHSNegative(N, hlsl::promote(-hlsl::dot(N, rayIntersected.direction))); ray_dir_info_t V; V.setDirection(-rayIntersected.direction); interaction_type interaction = interaction_type::create(V, N); diff --git a/31_HLSLPathTracer/app_resources/hlsl/scene_triangle_light.hlsl b/31_HLSLPathTracer/app_resources/hlsl/scene_triangle_light.hlsl index 92edfe5cd..ccac5b752 100644 --- a/31_HLSLPathTracer/app_resources/hlsl/scene_triangle_light.hlsl +++ b/31_HLSLPathTracer/app_resources/hlsl/scene_triangle_light.hlsl @@ -65,7 +65,7 @@ struct SceneTriangleLight : SceneBase vector3_type N = objectID.shapeType == PST_SPHERE ? getSphere(objectID.id).getNormal(intersection.position) : getTriangle(objectID.id).getNormalTimesArea(); N = hlsl::normalize(N); - intersection.geometricNormal = N; + intersection.geometricNormal = ieee754::flipSignIfRHSNegative(N, hlsl::promote(-hlsl::dot(N, rayIntersected.direction))); ray_dir_info_t V; V.setDirection(-rayIntersected.direction); interaction_type interaction = interaction_type::create(V, N); diff --git a/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl b/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl index 070cfe60d..2c8f2569e 100644 --- a/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl +++ b/66_HLSLBxDFTests/app_resources/test_compile.comp.hlsl @@ -60,43 +60,47 @@ void main(uint32_t3 ID : SV_DispatchThreadID) float3 L = float3(0,0,0); float3 q = float3(0,0,0); - sample_t s = lambertianBRDF.generate(anisointer, u.xy); + typename bxdf::reflection::SLambertian::anisocache_type _lcache; + sample_t s = lambertianBRDF.generate(anisointer, u.xy, _lcache); L += s.L.direction; - s = orenNayarBRDF.generate(anisointer, u.xy); + typename bxdf::reflection::SOrenNayar::anisocache_type _ocache; + s = orenNayarBRDF.generate(anisointer, u.xy, _ocache); L += s.L.direction; - quotient_pdf_t qp = orenNayarBRDF.quotient_and_pdf(s, isointer); + quotient_pdf_t qp = orenNayarBRDF.quotientAndWeight(s, isointer, _ocache); L -= qp.quotient(); s = beckmannAnisoBRDF.generate(anisointer, u.xy, cache); L += s.L.direction; - qp = beckmannAnisoBRDF.quotient_and_pdf(s, anisointer, cache); + qp = beckmannAnisoBRDF.quotientAndWeight(s, anisointer, cache); L -= qp.quotient(); s = ggxAnisoBRDF.generate(anisointer, u.xy, cache); L += s.L.direction; - qp = iridBRDF.quotient_and_pdf(s, anisointer, cache); + qp = iridBRDF.quotientAndWeight(s, anisointer, cache); L -= qp.quotient(); - qp = ggxAnisoBRDF.quotient_and_pdf(s, anisointer, cache); + qp = ggxAnisoBRDF.quotientAndWeight(s, anisointer, cache); L -= qp.quotient(); - s = lambertianBSDF.generate(anisointer, u); + typename bxdf::transmission::SLambertian::anisocache_type _tlcache; + s = lambertianBSDF.generate(anisointer, u, _tlcache); L += s.L.direction; - s = thinSmoothDielectricBSDF.generate(anisointer, u); + typename bxdf::transmission::SThinSmoothDielectric::anisocache_type _tscache; + s = thinSmoothDielectricBSDF.generate(anisointer, u, _tscache); L += s.L.direction; - qp = thinSmoothDielectricBSDF.quotient_and_pdf(s, isointer); + qp = thinSmoothDielectricBSDF.quotientAndWeight(s, isointer, _tscache); L -= qp.quotient(); s = ggxAnisoBSDF.generate(anisointer, u, cache); L += s.L.direction; - qp = ggxAnisoBSDF.quotient_and_pdf(s, anisointer, cache); + qp = ggxAnisoBSDF.quotientAndWeight(s, anisointer, cache); L -= qp.quotient(); buff[ID.x] = L; diff --git a/66_HLSLBxDFTests/app_resources/test_components.hlsl b/66_HLSLBxDFTests/app_resources/test_components.hlsl index 2570d68f9..dec73c67d 100644 --- a/66_HLSLBxDFTests/app_resources/test_components.hlsl +++ b/66_HLSLBxDFTests/app_resources/test_components.hlsl @@ -196,7 +196,8 @@ struct TestCTGenerateH : TestBxDF NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u.xy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u.xy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { @@ -207,7 +208,8 @@ struct TestCTGenerateH : TestBxDF } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) { diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 0a17fd836..186acf781 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -25,9 +25,10 @@ struct TestJacobian : TestBxDF NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::isointer, base_t::rc.u.xy); - sx = base_t::bxdf.generate(base_t::isointer, ux.xy); - sy = base_t::bxdf.generate(base_t::isointer, uy.xy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::isointer, base_t::rc.u.xy, _cache); + sx = base_t::bxdf.generate(base_t::isointer, ux.xy, _cache); + sy = base_t::bxdf.generate(base_t::isointer, uy.xy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { @@ -46,9 +47,10 @@ struct TestJacobian : TestBxDF } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - sx = base_t::bxdf.generate(base_t::anisointer, ux); - sy = base_t::bxdf.generate(base_t::anisointer, uy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, _cache); + sx = base_t::bxdf.generate(base_t::anisointer, ux, _cache); + sy = base_t::bxdf.generate(base_t::anisointer, uy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) { @@ -72,22 +74,23 @@ struct TestJacobian : TestBxDF NBL_IF_CONSTEXPR(!traits_t::IsMicrofacet) { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); - Li = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + typename BxDF::anisocache_type _cache; + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::isointer, _cache); + Li = base_t::bxdf.evalAndWeight(s, base_t::isointer); transmitted = base_t::isointer.getNdotV() * s.getNdotL() < 0.f; } NBL_IF_CONSTEXPR(traits_t::IsMicrofacet) { NBL_IF_CONSTEXPR(aniso) { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); - Li = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::anisointer, cache); + Li = base_t::bxdf.evalAndWeight(s, base_t::anisointer, cache); transmitted = cache.isTransmission(); } else { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); - Li = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::isointer, isocache); + Li = base_t::bxdf.evalAndWeight(s, base_t::isointer, isocache); transmitted = isocache.isTransmission(); } } @@ -118,7 +121,7 @@ struct TestJacobian : TestBxDF if (sampledLi.pdf() < bit_cast(numeric_limits::min)) // there's exceptional cases where pdf=0, so we check here to avoid adding all edge-cases, but quotient must be positive afterwards return BTR_NONE; - if (checkLt(Li, hlsl::promote(0.0)) || checkLt(sampledLi.quotient(), hlsl::promote(0.0))) + if (checkLt(Li.value(), hlsl::promote(0.0)) || checkLt(sampledLi.quotient(), hlsl::promote(0.0))) return BTR_ERROR_NEGATIVE_VAL; if (!checkLt(sampledLi.quotient(), hlsl::promote(bit_cast(numeric_limits::infinity)))) // importance sampler's job to prevent inf @@ -129,7 +132,7 @@ struct TestJacobian : TestBxDF // 2. quotient is positive and (1) already checked // So if we must have `eval == quotient*pdf` , then eval must also be positive // However for mixture of, or singular delta BxDF the bsdf can be less due to removal of Dirac-Delta lobes from the eval method, which is why allow `BTR_NONE` in this case - if (checkZero(Li, 1e-5) || checkZero(sampledLi.quotient(), 1e-5)) + if (checkZero(Li.value(), 1e-5) || checkZero(sampledLi.quotient(), 1e-5)) return BTR_NONE; if (hlsl::isnan(sampledLi.pdf())) @@ -160,14 +163,14 @@ struct TestJacobian : TestBxDF } float32_t3 quo_pdf = sampledLi.value(); - if (!testing::relativeApproxCompare(quo_pdf, Li, 1e-4)) + if (!testing::relativeApproxCompare(quo_pdf, Li.value(), 1e-4)) { #ifndef __HLSL_VERSION if (verbose) base_t::errMsg += std::format("transmitted={}, quotient*pdf=[{},{},{}] eval=[{},{},{}]", transmitted ? "true" : "false", quo_pdf.x, quo_pdf.y, quo_pdf.z, - Li.x, Li.y, Li.z); + Li.value().x, Li.value().y, Li.value().z); #endif return BTR_ERROR_PDF_EVAL_DIFF; } @@ -191,7 +194,7 @@ struct TestJacobian : TestBxDF sample_t s, sx, sy; quotient_pdf_t sampledLi; - float32_t3 Li; + value_weight_t Li; bool transmitted; bool verbose; }; @@ -224,7 +227,8 @@ struct TestReciprocity : TestBxDF NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(anisointer, base_t::rc.u.xy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(anisointer, base_t::rc.u.xy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { @@ -239,7 +243,8 @@ struct TestReciprocity : TestBxDF } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(anisointer, base_t::rc.u); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(anisointer, base_t::rc.u, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) { @@ -280,20 +285,20 @@ struct TestReciprocity : TestBxDF NBL_IF_CONSTEXPR(!traits_t::IsMicrofacet) { - Li = float32_t3(base_t::bxdf.eval(s, isointer)); - recLi = float32_t3(base_t::bxdf.eval(rec_s, rec_isointer)); + Li = base_t::bxdf.evalAndWeight(s, isointer); + recLi = base_t::bxdf.evalAndWeight(rec_s, rec_isointer); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { NBL_IF_CONSTEXPR(aniso) { - Li = float32_t3(base_t::bxdf.eval(s, anisointer, cache)); - recLi = float32_t3(base_t::bxdf.eval(rec_s, rec_anisointer, rec_cache)); + Li = base_t::bxdf.evalAndWeight(s, anisointer, cache); + recLi = base_t::bxdf.evalAndWeight(rec_s, rec_anisointer, rec_cache); } else { - Li = float32_t3(base_t::bxdf.eval(s, isointer, isocache)); - recLi = float32_t3(base_t::bxdf.eval(rec_s, rec_isointer, rec_isocache)); + Li = base_t::bxdf.evalAndWeight(s, isointer, isocache); + recLi = base_t::bxdf.evalAndWeight(rec_s, rec_isointer, rec_isocache); } } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) @@ -301,16 +306,16 @@ struct TestReciprocity : TestBxDF NBL_IF_CONSTEXPR(aniso) { anisointer.isotropic.pathOrigin = bxdf::PathOrigin::PO_SENSOR; - Li = float32_t3(base_t::bxdf.eval(s, anisointer, cache)); + Li = base_t::bxdf.evalAndWeight(s, anisointer, cache); rec_anisointer.isotropic.pathOrigin = bxdf::PathOrigin::PO_LIGHT; - recLi = float32_t3(base_t::bxdf.eval(rec_s, rec_anisointer, rec_cache)); + recLi = base_t::bxdf.evalAndWeight(rec_s, rec_anisointer, rec_cache); } else { isointer.pathOrigin = bxdf::PathOrigin::PO_SENSOR; - Li = float32_t3(base_t::bxdf.eval(s, isointer, isocache)); + Li = base_t::bxdf.evalAndWeight(s, isointer, isocache); rec_isointer.pathOrigin = bxdf::PathOrigin::PO_LIGHT; - recLi = float32_t3(base_t::bxdf.eval(rec_s, rec_isointer, rec_isocache)); + recLi = base_t::bxdf.evalAndWeight(rec_s, rec_isointer, rec_isocache); } } @@ -346,14 +351,14 @@ struct TestReciprocity : TestBxDF if (absNdotL <= bit_cast(numeric_limits::min)) return BTR_INVALID_TEST_CONFIG; - if (checkLt(Li, hlsl::promote(0.0))) + if (checkLt(Li.value(), hlsl::promote(0.0))) return BTR_ERROR_NEGATIVE_VAL; - if (checkZero(Li, 1e-5)) // we don't have a pdf to check like in the one above but + if (checkZero(Li.value(), 1e-5)) // we don't have a pdf to check like in the one above but return BTR_NONE; - float32_t3 a = Li / absNdotL; - float32_t3 b = recLi / hlsl::abs(rec_s.getNdotL()); + float32_t3 a = Li.value() / absNdotL; + float32_t3 b = recLi.value() / hlsl::abs(rec_s.getNdotL()); if (!(a == b)) // avoid division by 0 if (!testing::relativeApproxCompare(a, b, 1.25e-2)) { @@ -384,7 +389,7 @@ struct TestReciprocity : TestBxDF } sample_t s, rec_s; - float32_t3 Li, recLi; + value_weight_t Li, recLi; iso_interaction_t isointer, rec_isointer; aniso_interaction_t anisointer, rec_anisointer; bool transmitted; diff --git a/66_HLSLBxDFTests/app_resources/tests_common.hlsl b/66_HLSLBxDFTests/app_resources/tests_common.hlsl index 478cd1f55..c8f4778b6 100644 --- a/66_HLSLBxDFTests/app_resources/tests_common.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests_common.hlsl @@ -27,6 +27,7 @@ using sample_t = bxdf::SLightSample; using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = sampling::quotient_and_pdf; +using value_weight_t = sampling::value_and_weight; using iso_config_t = bxdf::SConfiguration; using aniso_config_t = bxdf::SConfiguration; @@ -628,7 +629,8 @@ struct CustomIsoMicrofacetConfiguration; using sample_type = LS; using spectral_type = Spectrum; - using quotient_pdf_type = sampling::quotient_and_pdf; + using quotient_weight_type = sampling::quotient_and_pdf; + using value_weight_type = sampling::value_and_weight; using isocache_type = MicrofacetCache; using anisocache_type = bxdf::SAnisotropicMicrofacetCache; }; diff --git a/66_HLSLBxDFTests/tests.h b/66_HLSLBxDFTests/tests.h index 442bac85c..80062afbb 100644 --- a/66_HLSLBxDFTests/tests.h +++ b/66_HLSLBxDFTests/tests.h @@ -39,7 +39,8 @@ struct TestModifiedWhiteFurnace : TestBxDF NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u.xy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u.xy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { @@ -54,7 +55,8 @@ struct TestModifiedWhiteFurnace : TestBxDF } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) { @@ -73,17 +75,18 @@ struct TestModifiedWhiteFurnace : TestBxDF NBL_IF_CONSTEXPR(!traits_t::IsMicrofacet) { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); + typename BxDF::anisocache_type _cache; + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::isointer, _cache); } NBL_IF_CONSTEXPR(traits_t::IsMicrofacet) { NBL_IF_CONSTEXPR(aniso) { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::anisointer, cache); } else { - sampledLi = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); + sampledLi = base_t::bxdf.quotientAndWeight(s, base_t::isointer, isocache); } } @@ -100,7 +103,11 @@ struct TestModifiedWhiteFurnace : TestBxDF } } - accumulatedQuotient = deltaQuotientSum / float(deltaSampleCount) + continuousQuotientSum / float(continuousSampleCount); + accumulatedQuotient = hlsl::promote(0.0); + if (deltaSampleCount > 0) + accumulatedQuotient += deltaQuotientSum / float(deltaSampleCount); + if (continuousSampleCount > 0) + accumulatedQuotient += continuousQuotientSum / float(continuousSampleCount); return BTR_NONE; } @@ -202,17 +209,17 @@ struct CalculatePdfSinTheta float pdf; NBL_IF_CONSTEXPR(!traits_t::IsMicrofacet) { - pdf = bxdf.pdf(s, isointer); + pdf = bxdf.forwardPdf(s, isointer); } NBL_IF_CONSTEXPR(traits_t::IsMicrofacet) { NBL_IF_CONSTEXPR(aniso) { - pdf = bxdf.pdf(s, anisointer, cache); + pdf = bxdf.forwardPdf(s, anisointer, cache); } else { - pdf = bxdf.pdf(s, isointer, cache.iso_cache); + pdf = bxdf.forwardPdf(s, isointer, cache.iso_cache); } } @@ -285,7 +292,8 @@ struct TestChi2 : TestBxDF NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u.xy); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u.xy, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BRDF && traits_t::IsMicrofacet) { @@ -296,7 +304,8 @@ struct TestChi2 : TestBxDF } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && !traits_t::IsMicrofacet) { - s = base_t::bxdf.generate(base_t::anisointer, u); + typename BxDF::anisocache_type _cache; + s = base_t::bxdf.generate(base_t::anisointer, u, _cache); } NBL_IF_CONSTEXPR(traits_t::type == bxdf::BT_BSDF && traits_t::IsMicrofacet) {