From 868bfec21be0fa0f69dd12910de9aaba735acb55 Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Wed, 7 Jun 2023 17:19:36 +0200 Subject: [PATCH 01/15] [vsp] First implementation of volume scatter probability (VSP) guiding --- openpgl/api/api.cpp | 14 + openpgl/data/PathSegmentDataStorage.h | 5 + openpgl/data/SampleData.h | 8 +- .../ISurfaceSamplingDistribution.h | 2 + .../directional/IVolumeSamplingDistribution.h | 2 + openpgl/directional/dqt/DQTFactory.h | 7 + .../dqt/DQTSurfaceSamplingDistribution.h | 5 + .../dqt/DQTVolumeSamplingDistribution.h | 5 + .../vmm/AdaptiveSplitandMergeFactory.h | 13 + .../vmm/ParallaxAwareVonMisesFisherMixture.h | 99 ++++++- ...llaxAwareVonMisesFisherWeightedEMFactory.h | 262 +++++++++++++++++- .../vmm/VMMSurfaceSamplingDistribution.h | 5 + .../vmm/VMMVolumeSamplingDistribution.h | 5 + openpgl/field/Field.h | 8 + openpgl/include/openpgl/common.h | 7 + .../openpgl/cpp/SurfaceSamplingDistribution.h | 8 + .../openpgl/cpp/VolumeSamplingDistribution.h | 7 + openpgl/include/openpgl/data.h | 4 +- .../openpgl/surfacesamplingdistribution.h | 3 + .../openpgl/volumesamplingdistribution.h | 3 + 20 files changed, 452 insertions(+), 20 deletions(-) diff --git a/openpgl/api/api.cpp b/openpgl/api/api.cpp index 9e40343c..e1c19320 100644 --- a/openpgl/api/api.cpp +++ b/openpgl/api/api.cpp @@ -609,6 +609,13 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglSurfaceSamplingDistributionGetId(PGLSur return gSurfaceSamplingDistribution->getId(); } +extern "C" OPENPGL_DLLEXPORT float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, + bool contributionBased) +{ + ISurfaceSamplingDistribution *gSurfaceSamplingDistribution = (ISurfaceSamplingDistribution *)surfaceSamplingDistribution; + return gSurfaceSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); +} + extern "C" OPENPGL_DLLEXPORT bool pglSurfaceSamplingDistributionValidate(PGLSurfaceSamplingDistribution surfaceSamplingDistribution) { ISurfaceSamplingDistribution *gSurfaceSamplingDistribution = (ISurfaceSamplingDistribution *)surfaceSamplingDistribution; @@ -707,6 +714,13 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglVolumeSamplingDistributionGetId(PGLVolu return gVolumeSamplingDistribution->getId(); } +extern "C" OPENPGL_DLLEXPORT float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution volumeSamplingDistribution, pgl_vec3f direction, + bool contributionBased) +{ + IVolumeSamplingDistribution *gVolumeSamplingDistribution = (IVolumeSamplingDistribution *)volumeSamplingDistribution; + return gVolumeSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); +} + extern "C" OPENPGL_DLLEXPORT bool pglVolumeSamplingDistributionValidate(PGLVolumeSamplingDistribution volumeSamplingDistribution) { IVolumeSamplingDistribution *gVolumeSamplingDistribution = (IVolumeSamplingDistribution *)volumeSamplingDistribution; diff --git a/openpgl/data/PathSegmentDataStorage.h b/openpgl/data/PathSegmentDataStorage.h index 0f714232..87d774e0 100644 --- a/openpgl/data/PathSegmentDataStorage.h +++ b/openpgl/data/PathSegmentDataStorage.h @@ -260,6 +260,11 @@ struct PathSegmentDataStorage flags |= SampleData::EInsideVolume; } + if (m_segmentStorage[i + 1].volumeScatter) + { + flags |= SampleData::ENextEventVolume; + } + bool directLightSample = false; #ifdef OPENPGL_RADIANCE_CACHES float misWeight = 1.f; diff --git a/openpgl/data/SampleData.h b/openpgl/data/SampleData.h index aee3a049..fc991a05 100644 --- a/openpgl/data/SampleData.h +++ b/openpgl/data/SampleData.h @@ -22,7 +22,8 @@ typedef PGLSampleData SampleData; enum SampleData_Flags { EInsideVolume = 1 << 0, // point does not represent any real scene intersection point - EDirectLight = 1 << 1 // if the samples represents direct light from a light source + EDirectLight = 1 << 1, // if the samples represents direct light from a light source + ENextEventVolume = 1 << 2 }; inline bool isValid(const SampleData &dsd) @@ -86,6 +87,11 @@ inline bool isDirectLight(const SampleData &sd) return (sd.flags & EDirectLight); } +inline bool isNextEventVolume(const SampleData &sd) +{ + return (sd.flags & ENextEventVolume); +} + inline std::string toString(const SampleData &sd) { std::stringstream ss; diff --git a/openpgl/directional/ISurfaceSamplingDistribution.h b/openpgl/directional/ISurfaceSamplingDistribution.h index e1fb19b1..f67be895 100644 --- a/openpgl/directional/ISurfaceSamplingDistribution.h +++ b/openpgl/directional/ISurfaceSamplingDistribution.h @@ -57,6 +57,8 @@ struct ISurfaceSamplingDistribution virtual const IRegion *getRegion() const = 0; + virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; + protected: // const IRegion* m_region {nullptr}; uint32_t m_id{0}; diff --git a/openpgl/directional/IVolumeSamplingDistribution.h b/openpgl/directional/IVolumeSamplingDistribution.h index f2431771..0bc20602 100644 --- a/openpgl/directional/IVolumeSamplingDistribution.h +++ b/openpgl/directional/IVolumeSamplingDistribution.h @@ -59,6 +59,8 @@ struct IVolumeSamplingDistribution virtual const IRegion *getRegion() const = 0; + virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; + protected: // const IRegion* m_region {nullptr}; uint32_t m_id{0}; diff --git a/openpgl/directional/dqt/DQTFactory.h b/openpgl/directional/dqt/DQTFactory.h index cc4e889d..07b5c095 100644 --- a/openpgl/directional/dqt/DQTFactory.h +++ b/openpgl/directional/dqt/DQTFactory.h @@ -154,6 +154,11 @@ class DirectionalQuadtreeFactory is.read(reinterpret_cast(nodes.data()), size * sizeof(nodes[0])); }; + float getNumSamples() const + { + return numSamples; + }; + // TODO: Needs to be implmented bool operator==(const Statistics &b) const { @@ -175,6 +180,8 @@ class DirectionalQuadtreeFactory const SampleStatistics &sampleStatistics) const {} + void updateVolumeScatterProbability(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples) const {} + void fit(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const Configuration &cfg, FittingStatistics &fitStats) { for (uint32_t i = 0; i < 5; i++) diff --git a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h index e4e8406a..e118bf7b 100644 --- a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h @@ -87,6 +87,11 @@ struct DQTSurfaceSamplingDistribution : public ISurfaceSamplingDistribution m_region = region; } + float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + { + return 0.f; + } + private: TDirectionalQuadtree distribution; const IRegion *m_region{nullptr}; diff --git a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h index 8607b4f0..fc0c72f0 100644 --- a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h @@ -93,6 +93,11 @@ struct DQTVolumeSamplingDistribution : public IVolumeSamplingDistribution m_region = region; } + float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + { + return 0.f; + } + private: TDirectionalQuadtree distribution; const IRegion *m_region{nullptr}; diff --git a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h index aaabb1b0..2bb92b4a 100644 --- a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h +++ b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h @@ -95,6 +95,10 @@ struct AdaptiveSplitAndMergeFactory return sufficientStatistics.getNumComponents(); } + inline float getNumSamples() const + { + return sufficientStatistics.getNumSamples(); + }; std::string toString() const; bool operator==(const Statistics &b) const; @@ -122,6 +126,8 @@ struct AdaptiveSplitAndMergeFactory void updateFluenceEstimate(VMM &vmm, const SampleData *samples, const size_t numSamples, const size_t numZeroValueSamples, const SampleStatistics &sampleStatistics) const; + void updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples) const; + std::string toString() const { std::ostringstream oss; @@ -463,4 +469,11 @@ void AdaptiveSplitAndMergeFactory::updateFluenceEstimate(VMM & factory.updateFluenceEstimate(vmm, samples, numSamples, numZeroValueSamples, sampleStatistics); } +template +void AdaptiveSplitAndMergeFactory::updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples) const +{ + WeightedEMFactory factory = WeightedEMFactory(); + factory.updateVolumeScatterProbability(vmm, stats.sufficientStatistics, samples, numSamples); +} + } // namespace openpgl diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h index 70b0d00a..03a71711 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h @@ -76,6 +76,9 @@ struct ParallaxAwareVonMisesFisherMixture embree::vfloat _distances[NumVectors]; Point3 _pivotPosition{0.0f, 0.0f, 0.0f}; + embree::vfloat _volumeScatterFirstMomentProbabilityWeights[NumVectors]; + embree::vfloat _volumeScatterSecondMomentProbabilityWeights[NumVectors]; + #ifdef OPENPGL_RADIANCE_CACHES // fluence attributes // float _fluence {0.0f}; @@ -152,15 +155,12 @@ struct ParallaxAwareVonMisesFisherMixture void setComponentDistance(const size_t &idx, const float &distance); - void decay(const float alpha) - { -#ifdef OPENPGL_RADIANCE_CACHES - _numFluenceSamples *= alpha; -#endif - } + void decay(const float alpha); bool isValid() const; + float volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const; + std::string toString() const; void _calculateNormalization(); @@ -256,6 +256,8 @@ std::string ParallaxAwareVonMisesFisherMixture_eMinus2Kappa[tmp.quot][tmp.rem]; ss << "\t meanCosine: " << this->_meanCosines[tmp.quot][tmp.rem]; ss << "\t distance: " << _distances[tmp.quot][tmp.rem]; + ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterFirstMomentProbabilityWeights[tmp.quot][tmp.rem]; + ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterSecondMomentProbabilityWeights[tmp.quot][tmp.rem]; #ifdef OPENPGL_RADIANCE_CACHES ss << "\t fluenceRGBWeightWithMIS: " << _fluenceRGBWeightsWithMIS[tmp.quot].x[tmp.rem] << "\t" << _fluenceRGBWeightsWithMIS[tmp.quot].y[tmp.rem] << "\t" << _fluenceRGBWeightsWithMIS[tmp.quot].z[tmp.rem]; @@ -304,6 +306,9 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeightsWithMIS); serializeVec3Vectors(stream, _fluenceRGBWeights); #endif + serializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); + serializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); + stream.write(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.write(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -530,6 +557,9 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeightsWithMIS); deserializeVec3Vectors(stream, _fluenceRGBWeights); #endif + deserializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); + deserializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); + stream.read(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.read(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -591,6 +621,16 @@ bool ParallaxAwareVonMisesFisherMixture= 0.0f; OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(_volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem]); + valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; + valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(_volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem]); + valid = valid && _volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; + valid = valid && _volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; + OPENPGL_ASSERT(valid); } // check unused componets @@ -632,6 +672,14 @@ bool ParallaxAwareVonMisesFisherMixture +void ParallaxAwareVonMisesFisherMixture::decay(float alpha) +{ +#ifdef OPENPGL_RADIANCE_CACHES + _numFluenceSamples *= alpha; +#endif +} + template void ParallaxAwareVonMisesFisherMixture::_calculateNormalization() { @@ -1189,6 +1245,37 @@ bool ParallaxAwareVonMisesFisherMixture +float ParallaxAwareVonMisesFisherMixture::volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const +{ + const int cnt = (_numComponents + VecSize - 1) / VecSize; + + embree::vfloat volumeScatterProbability = {0.0f}; + embree::vfloat pdf = {0.0f}; + embree::Vec3> vec3Direction(direction[0], direction[1], direction[2]); + + const embree::vfloat ones(1.0f); + const embree::vfloat zeros(0.0f); + + for (int k = 0; k < cnt; k++) + { + const embree::vfloat cosTheta = embree::dot(vec3Direction, _meanDirections[k]); + const embree::vfloat cosThetaMinusOne = embree::min(cosTheta - ones, zeros); + const embree::vfloat eval = _weights[k] * _normalizations[k] * embree::fastapprox::exp>(_kappas[k] * cosThetaMinusOne); + pdf += eval; + if (contributionBased) + { + volumeScatterProbability += _volumeScatterFirstMomentProbabilityWeights[k] * eval; + } + else + { + volumeScatterProbability += _volumeScatterSecondMomentProbabilityWeights[k] * eval; + } + } + + return reduce_add(volumeScatterProbability) / reduce_add(pdf); +} + #ifdef OPENPGL_RADIANCE_CACHES template Vector3 ParallaxAwareVonMisesFisherMixture::incomingRadiance(const Vector3 &direction, const bool directLightMIS) const diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h index 22cf1651..986eedb9 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h @@ -97,6 +97,13 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory embree::Vec3 > sumOfWeightedDirections[VMM::NumVectors]; embree::vfloat sumOfWeightedStats[VMM::NumVectors]; + embree::vfloat volumeContributionFirstMomentWeights[VMM::NumVectors]; + embree::vfloat surfaceContributionFirstMomentWeights[VMM::NumVectors]; + embree::vfloat volumeContributionSecondMomentWeights[VMM::NumVectors]; + embree::vfloat surfaceContributionSecondMomentWeights[VMM::NumVectors]; + embree::vfloat volumeSampleNumberWeights[VMM::NumVectors]; + embree::vfloat surfaceSampleNumberWeights[VMM::NumVectors]; + float sumWeights{0.f}; float numSamples{0.f}; float overallNumSamples{0.f}; @@ -115,6 +122,8 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory void clear(size_t _numComponents); + void clearComponentStats(const size_t &idx); + void clearAll(); virtual void normalize(const float &_numSamples); @@ -202,6 +211,8 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory void updateComponentDistances(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; + void updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; + private: void _initUniformDirections(); @@ -312,6 +323,30 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && embree::isvalid(sumOfDistanceWeightes[tmpK.quot][tmpK.rem]); valid = valid && sumOfDistanceWeightes[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeSampleNumberWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeSampleNumberWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceSampleNumberWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceSampleNumberWeights[tmpK.quot][tmpK.rem] >= 0.0f; + OPENPGL_ASSERT(valid); } for (size_t k = numComponents; k < VMM::MaxComponents; k++) @@ -332,6 +367,30 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && embree::isvalid(sumOfDistanceWeightes[tmpK.quot][tmpK.rem]); valid = valid && sumOfDistanceWeightes[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(volumeSampleNumberWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeSampleNumberWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); + + valid = valid && embree::isvalid(surfaceSampleNumberWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceSampleNumberWeights[tmpK.quot][tmpK.rem] == 0.0f; + OPENPGL_ASSERT(valid); } valid = valid && embree::isvalid(numSamples); @@ -356,6 +415,12 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.write(reinterpret_cast(&overallNumSamples), sizeof(float)); stream.write(reinterpret_cast(&numComponents), sizeof(size_t)); stream.write(reinterpret_cast(&normalized), sizeof(bool)); + serializeFloatVectors(stream, volumeContributionFirstMomentWeights); + serializeFloatVectors(stream, surfaceContributionFirstMomentWeights); + serializeFloatVectors(stream, volumeContributionSecondMomentWeights); + serializeFloatVectors(stream, surfaceContributionSecondMomentWeights); + serializeFloatVectors(stream, volumeSampleNumberWeights); + serializeFloatVectors(stream, surfaceSampleNumberWeights); } template @@ -369,6 +434,12 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.read(reinterpret_cast(&overallNumSamples), sizeof(float)); stream.read(reinterpret_cast(&numComponents), sizeof(size_t)); stream.read(reinterpret_cast(&normalized), sizeof(bool)); + deserializeFloatVectors(stream, volumeContributionFirstMomentWeights); + deserializeFloatVectors(stream, surfaceContributionFirstMomentWeights); + deserializeFloatVectors(stream, volumeContributionSecondMomentWeights); + deserializeFloatVectors(stream, surfaceContributionSecondMomentWeights); + deserializeFloatVectors(stream, volumeSampleNumberWeights); + deserializeFloatVectors(stream, surfaceSampleNumberWeights); } template @@ -386,6 +457,13 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[k] = zeros; sumOfDistanceWeightes[k] = zeros; + + volumeContributionFirstMomentWeights[k] = 0.0f; + surfaceContributionFirstMomentWeights[k] = 0.0f; + volumeContributionSecondMomentWeights[k] = 0.0f; + surfaceContributionSecondMomentWeights[k] = 0.0f; + volumeSampleNumberWeights[k] = 0.0f; + surfaceSampleNumberWeights[k] = 0.0f; } sumWeights = 0.0f; @@ -393,6 +471,26 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS normalized = false; } +template +void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientStatistics::clearComponentStats(const size_t &idx) +{ + const div_t tmpIdx = div(idx, VMM::VectorSize); + + sumOfWeightedDirections[tmpIdx.quot].x[tmpIdx.rem] = 0.f; + sumOfWeightedDirections[tmpIdx.quot].y[tmpIdx.rem] = 0.f; + sumOfWeightedDirections[tmpIdx.quot].z[tmpIdx.rem] = 0.f; + sumOfWeightedStats[tmpIdx.quot][tmpIdx.rem] = 0.f; + + sumOfDistanceWeightes[tmpIdx.quot][tmpIdx.rem] = 0.f; + + volumeContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + surfaceContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + volumeContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + surfaceContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + volumeSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + surfaceSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; +} + template void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientStatistics::clearAll() { @@ -410,6 +508,13 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[k] *= alpha; sumOfDistanceWeightes[k] *= alpha; + + volumeContributionFirstMomentWeights[k] *= alpha; + surfaceContributionFirstMomentWeights[k] *= alpha; + volumeContributionSecondMomentWeights[k] *= alpha; + surfaceContributionSecondMomentWeights[k] *= alpha; + volumeSampleNumberWeights[k] *= alpha; + surfaceSampleNumberWeights[k] *= alpha; } numSamples *= alpha; @@ -471,6 +576,13 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS std::swap(sumOfWeightedDirections[tmpIdx0.quot].z[tmpIdx0.rem], sumOfWeightedDirections[tmpIdx1.quot].z[tmpIdx1.rem]); std::swap(sumOfWeightedStats[tmpIdx0.quot][tmpIdx0.rem], sumOfWeightedStats[tmpIdx1.quot][tmpIdx1.rem]); std::swap(sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem], sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]); + + std::swap(volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); } template @@ -488,18 +600,15 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem] += sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]; // copying the statistics of the last component to the position of component 1 - sumOfWeightedDirections[tmpIdx1.quot].x[tmpIdx1.rem] = sumOfWeightedDirections[tmpIdx2.quot].x[tmpIdx2.rem]; - sumOfWeightedDirections[tmpIdx1.quot].y[tmpIdx1.rem] = sumOfWeightedDirections[tmpIdx2.quot].y[tmpIdx2.rem]; - sumOfWeightedDirections[tmpIdx1.quot].z[tmpIdx1.rem] = sumOfWeightedDirections[tmpIdx2.quot].z[tmpIdx2.rem]; - sumOfWeightedStats[tmpIdx1.quot][tmpIdx1.rem] = sumOfWeightedStats[tmpIdx2.quot][tmpIdx2.rem]; - sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem] = sumOfDistanceWeightes[tmpIdx2.quot][tmpIdx2.rem]; - - // reseting the statistics of the last component - sumOfWeightedDirections[tmpIdx2.quot].x[tmpIdx2.rem] = 0.0f; - sumOfWeightedDirections[tmpIdx2.quot].y[tmpIdx2.rem] = 0.0f; - sumOfWeightedDirections[tmpIdx2.quot].z[tmpIdx2.rem] = 0.0f; - sumOfWeightedStats[tmpIdx2.quot][tmpIdx2.rem] = 0.0f; - sumOfDistanceWeightes[tmpIdx2.quot][tmpIdx2.rem] = 0.0f; + volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; + surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; + volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; + surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; + volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; + surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; + + swapComponentStats(idx1, numComponents - 1); + clearComponentStats(numComponents - 1); numComponents--; } @@ -534,6 +643,22 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[tmpI.quot][tmpI.rem] = tmp; sumOfDistanceWeightes[tmpJ.quot][tmpJ.rem] = tmp; + float weight0 = 0.5f; + float weight1 = 0.5f; + + volumeContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; + volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem] *= weight0; + surfaceContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; + surfaceContributionFirstMomentWeights[tmpI.quot][tmpI.rem] *= weight0; + volumeContributionSecondMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionSecondMomentWeights[tmpI.quot][tmpI.rem]; + volumeContributionSecondMomentWeights[tmpI.quot][tmpI.rem] *= weight0; + surfaceContributionSecondMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionSecondMomentWeights[tmpI.quot][tmpI.rem]; + surfaceContributionSecondMomentWeights[tmpI.quot][tmpI.rem] *= weight0; + volumeSampleNumberWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeSampleNumberWeights[tmpI.quot][tmpI.rem]; + volumeSampleNumberWeights[tmpI.quot][tmpI.rem] *= weight0; + surfaceSampleNumberWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceSampleNumberWeights[tmpI.quot][tmpI.rem]; + surfaceSampleNumberWeights[tmpI.quot][tmpI.rem] *= weight0; + numComponents += 1; OPENPGL_ASSERT(!std::isnan(sumOfWeightedDirections[tmpI.quot].x[tmpI.rem]) && std::isfinite(sumOfWeightedDirections[tmpI.quot].x[tmpI.rem])); @@ -1615,4 +1740,117 @@ std::string ParallaxAwareVonMisesFisherWeightedEMFactory::Part return ss.str(); } +template +void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, + const size_t numSamples) const +{ + // OPENPGL_ASSERT(vmm.isValid()); + + if (numSamples == 0) + { + return; + } + + const int cnt = (vmm._numComponents + VMM::VectorSize - 1) / VMM::VectorSize; + const int rem = vmm._numComponents % VMM::VectorSize; + + const embree::vfloat zeros(0.0f); + const embree::vfloat ones(1.0f); + + typename VMM::SoftAssignment softAssign; + + for (size_t n = 0; n < numSamples; n++) + { + const float weight = samples[n].weight; + pgl_vec3f direction = samples[n].direction; + const Vector3 sampleDirection(direction.x, direction.y, direction.z); + + if (vmm.softAssignment(sampleDirection, softAssign)) + { + for (size_t k = 0; k < cnt; k++) + { + if (isNextEventVolume(samples[n])) + { + sufficientStats.volumeContributionFirstMomentWeights[k] += weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionFirstMomentWeights[k])); + sufficientStats.volumeContributionSecondMomentWeights[k] += weight * weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionSecondMomentWeights[k])); + sufficientStats.volumeSampleNumberWeights[k] += softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeSampleNumberWeights[k])); + } + else + { + sufficientStats.surfaceContributionFirstMomentWeights[k] += weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionFirstMomentWeights[k])); + sufficientStats.surfaceContributionSecondMomentWeights[k] += weight * weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionSecondMomentWeights[k])); + sufficientStats.surfaceSampleNumberWeights[k] += softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceSampleNumberWeights[k])); + } + } + } + } + + if (rem > 0) + { + for (size_t i = rem; i < VMM::VectorSize; i++) + { + vmm._volumeScatterFirstMomentProbabilityWeights[cnt - 1][i] = 0.0f; + vmm._volumeScatterSecondMomentProbabilityWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionFirstMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionFirstMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeSampleNumberWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceSampleNumberWeights[cnt - 1][i] = 0.0f; + } + } + + for (size_t k = 0; k < cnt; k++) + { + embree::vfloat numVolSamples = sufficientStats.volumeSampleNumberWeights[k]; + embree::vfloat numSurfSamples = sufficientStats.surfaceSampleNumberWeights[k]; + embree::vfloat numSurfVolSamples = numVolSamples + numSurfSamples; + embree::vfloat estPVol = select(numSurfVolSamples > FLT_EPSILON, numVolSamples / numSurfVolSamples, zeros); + + embree::vfloat volumeContributionFirstMomentWeight = + select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionFirstMomentWeights[k] / numVolSamples, zeros); + embree::vfloat surfaceContributionFirstMomentWeight = + select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionFirstMomentWeights[k] / numSurfSamples, zeros); + embree::vfloat sumContributionFirstMomentWeight = + (surfaceContributionFirstMomentWeight * (ones - estPVol)) + (volumeContributionFirstMomentWeight * estPVol); + vmm._volumeScatterFirstMomentProbabilityWeights[k] = + select(sumContributionFirstMomentWeight > FLT_EPSILON, (volumeContributionFirstMomentWeight * estPVol) / sumContributionFirstMomentWeight, zeros); + + embree::vfloat volumeContributionSecondMomentWeight = + select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionSecondMomentWeights[k] / numVolSamples, zeros); + volumeContributionSecondMomentWeight *= (estPVol * estPVol); + volumeContributionSecondMomentWeight = select(volumeContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(volumeContributionSecondMomentWeight), zeros); + + embree::vfloat surfaceContributionSecondMomentWeight = + select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionSecondMomentWeights[k] / numSurfSamples, zeros); + surfaceContributionSecondMomentWeight *= (ones - estPVol) * (ones - estPVol); + surfaceContributionSecondMomentWeight = select(surfaceContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(surfaceContributionSecondMomentWeight), zeros); + + embree::vfloat sumContributionSecondMomentWeight = surfaceContributionSecondMomentWeight + volumeContributionSecondMomentWeight; + vmm._volumeScatterSecondMomentProbabilityWeights[k] = + select(sumContributionSecondMomentWeight > FLT_EPSILON, volumeContributionSecondMomentWeight / sumContributionSecondMomentWeight, zeros); + } + + if (rem > 0) + { + for (size_t i = rem; i < VMM::VectorSize; i++) + { + vmm._volumeScatterFirstMomentProbabilityWeights[cnt - 1][i] = 0.0f; + vmm._volumeScatterSecondMomentProbabilityWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionFirstMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionFirstMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeSampleNumberWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceSampleNumberWeights[cnt - 1][i] = 0.0f; + } + } +} + } // namespace openpgl diff --git a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h index b0ba74f2..e81a7a6c 100644 --- a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h @@ -155,6 +155,11 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMSurfaceSamplingDistributio { m_region = region; } + + float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + { + return m_liDistribution.volumeScatterProbability(dir, contributionBased); + } }; } // namespace openpgl \ No newline at end of file diff --git a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h index 89a2d30e..82371331 100644 --- a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h @@ -187,6 +187,11 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMVolumeSamplingDistribution { m_region = region; } + + float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + { + return m_liDistribution.volumeScatterProbability(dir, contributionBased); + } }; } // namespace openpgl \ No newline at end of file diff --git a/openpgl/field/Field.h b/openpgl/field/Field.h index ff4afe82..1d61f0c7 100644 --- a/openpgl/field/Field.h +++ b/openpgl/field/Field.h @@ -462,6 +462,9 @@ struct Field zeroValueSamples.data() + regionStorage.second.m_is_begin, regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif + m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, + samples.data() + regionStorage.second.m_begin, + regionStorage.second.m_end - regionStorage.second.m_begin); // TODO: we should move setting the pivot to the factory regionStorage.first.distribution._pivotPosition = sampleMean; regionStorage.first.valid = regionStorage.first.distribution.isValid(); @@ -537,6 +540,7 @@ struct Field OPENPGL_ASSERT(regionStorage.first.trainingStatistics.sufficientStatistics.isValid()); } typename DirectionalDistributionFactory::FittingStatistics fittingStats; + float numSamples = regionStorage.first.trainingStatistics.getNumSamples(); m_distributionFactory.prepareSamples(samples.data() + regionStorage.second.m_begin, regionStorage.second.m_end - regionStorage.second.m_begin, regionStorage.first.sampleStatistics, m_distributionFactorySettings); if (regionStorage.first.initialized) @@ -558,6 +562,9 @@ struct Field zeroValueSamples.data() + regionStorage.second.m_is_begin, regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif + m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, + samples.data() + regionStorage.second.m_begin, + regionStorage.second.m_end - regionStorage.second.m_begin); regionStorage.first.valid = regionStorage.first.isValid(); #ifdef OPENPGL_DEBUG_MODE if (!regionStorage.first.valid) @@ -577,6 +584,7 @@ struct Field if (regionStorage.first.splitFlag) { regionStorage.first.trainingStatistics.decay(this->m_decayOnSpatialSplit); + regionStorage.first.distribution.decay(this->m_decayOnSpatialSplit); regionStorage.first.splitFlag = false; } } diff --git a/openpgl/include/openpgl/common.h b/openpgl/include/openpgl/common.h index 264f3a1f..40b21b03 100644 --- a/openpgl/include/openpgl/common.h +++ b/openpgl/include/openpgl/common.h @@ -171,6 +171,13 @@ inline void pglVec3fAdd(pgl_vec3f &veca, const pgl_vec3f &vecb) veca.z += vecb.z; } +inline void pglVec3fMultiply(pgl_vec3f &veca, const pgl_vec3f &vecb) +{ + veca.x *= vecb.x; + veca.y *= vecb.y; + veca.z *= vecb.z; +} + inline void pglVec2f(pgl_vec2f &vec, const float x, const float y) { vec.x = x; diff --git a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h index bafa72cf..ae7da55b 100644 --- a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h @@ -146,6 +146,8 @@ struct SurfaceSamplingDistribution */ pgl_vec3f Irradiance(pgl_vec3f &normal, const bool directLightMIS) const; #endif + + float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; /////////////////////////////////////// /// Future plans /////////////////////////////////////// @@ -286,5 +288,11 @@ OPENPGL_INLINE pgl_vec3f SurfaceSamplingDistribution::Irradiance(pgl_vec3f &norm } #endif +OPENPGL_INLINE float SurfaceSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const +{ + OPENPGL_ASSERT(m_surfaceSamplingDistributionHandle); + return pglSurfaceSamplingDistributionVolumeScatterProbability(m_surfaceSamplingDistributionHandle, direction, contributionBased); +} + } // namespace cpp } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h index 6592cd94..ce49fa80 100644 --- a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h @@ -164,6 +164,7 @@ struct VolumeSamplingDistribution pgl_vec3f Fluence(const bool directLightMIS) const; #endif + float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; /////////////////////////////////////// /// Future plans /////////////////////////////////////// @@ -308,5 +309,11 @@ OPENPGL_INLINE pgl_vec3f VolumeSamplingDistribution::Fluence(const bool directLi } #endif +OPENPGL_INLINE float VolumeSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const +{ + OPENPGL_ASSERT(m_volumeSamplingDistributionHandle); + return pglVolumeSamplingDistributionVolumeScatterProbability(m_volumeSamplingDistributionHandle, direction, contributionBased); +} + } // namespace cpp } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/data.h b/openpgl/include/openpgl/data.h index 5f55051c..f0cfb4ec 100644 --- a/openpgl/include/openpgl/data.h +++ b/openpgl/include/openpgl/data.h @@ -25,7 +25,9 @@ struct PGLSampleData /// point does not represent any real scene intersection point EInsideVolume = 1 << 0, /// if the samples represents direct light from a light source - EDirectLight = 1 << 1 + EDirectLight = 1 << 1, + + ENextEventVolume = 1 << 2 }; /// the position of the sample (i.e., at which energy arrives) diff --git a/openpgl/include/openpgl/surfacesamplingdistribution.h b/openpgl/include/openpgl/surfacesamplingdistribution.h index ad922cbb..bdc166fe 100644 --- a/openpgl/include/openpgl/surfacesamplingdistribution.h +++ b/openpgl/include/openpgl/surfacesamplingdistribution.h @@ -51,6 +51,9 @@ typedef ManagedObject SurfaceSamplingDistribution; OPENPGL_CORE_INTERFACE pgl_vec3f pglSurfaceSamplingDistributionOutgoingRadiance(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction); #endif + OPENPGL_CORE_INTERFACE float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, + bool contributionBased); + #ifdef __cplusplus } // extern "C" #endif \ No newline at end of file diff --git a/openpgl/include/openpgl/volumesamplingdistribution.h b/openpgl/include/openpgl/volumesamplingdistribution.h index c4377c5c..c634e5dd 100644 --- a/openpgl/include/openpgl/volumesamplingdistribution.h +++ b/openpgl/include/openpgl/volumesamplingdistribution.h @@ -54,6 +54,9 @@ typedef ManagedObject VolumeSamplingDistribution; OPENPGL_CORE_INTERFACE pgl_vec3f pglVolumeSamplingDistributionFluence(PGLVolumeSamplingDistribution volumeSamplingDistribution, const bool directLightMIS); #endif + OPENPGL_CORE_INTERFACE float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution VolumeSamplingDistribution, pgl_vec3f direction, + bool contributionBased); + #ifdef __cplusplus } // extern "C" #endif \ No newline at end of file From c3e6528ffdd780175b70b1457d7e0768b0320878 Mon Sep 17 00:00:00 2001 From: "Herholz, Sebastian" Date: Fri, 16 Aug 2024 14:28:27 +0200 Subject: [PATCH 02/15] [vsp] Adding CMake parameter OPENPGL_EF_VSP_GUIDING to turn VSP guiding on or off --- CMakeLists.txt | 1 + openpgl/CMakeLists.txt | 10 +++++ openpgl/api/api.cpp | 4 ++ .../ISurfaceSamplingDistribution.h | 2 + .../directional/IVolumeSamplingDistribution.h | 2 + .../dqt/DQTSurfaceSamplingDistribution.h | 2 + .../dqt/DQTVolumeSamplingDistribution.h | 2 + .../vmm/ParallaxAwareVonMisesFisherMixture.h | 30 +++++++++++--- ...llaxAwareVonMisesFisherWeightedEMFactory.h | 39 ++++++++++++------- .../vmm/VMMSurfaceSamplingDistribution.h | 2 + .../vmm/VMMVolumeSamplingDistribution.h | 2 + openpgl/field/Field.h | 5 ++- .../openpgl/cpp/SurfaceSamplingDistribution.h | 5 ++- .../openpgl/cpp/VolumeSamplingDistribution.h | 4 ++ openpgl/include/openpgl/defines.h.in | 1 + .../openpgl/surfacesamplingdistribution.h | 2 + .../openpgl/volumesamplingdistribution.h | 3 +- 17 files changed, 94 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f683960..c61d2de3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ option(OPENPGL_BUILD_CHECK_TOOL "Build check tool application." OFF) try_compile(COMPILER_SUPPORTS_ARM_NEON "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/cmake/check_arm_neon.cpp") OPTION(OPENPGL_EF_RADIANCE_CACHES "Enables experimental feature (ir)radiance caches." OFF) +OPTION(OPENPGL_EF_VSP_GUIDING "Enables experimental feature volume scatter probability guiding." OFF) OPTION(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER "Enables experimental feature ImageSpaceGuidignBuffer." OFF) OPTION(OPENPGL_DIRECTION_COMPRESSION "Using 32-Bit compression to represent directions." OFF) diff --git a/openpgl/CMakeLists.txt b/openpgl/CMakeLists.txt index e649e9ba..fc2582b0 100644 --- a/openpgl/CMakeLists.txt +++ b/openpgl/CMakeLists.txt @@ -46,6 +46,11 @@ if(OPENPGL_EF_RADIANCE_CACHES) target_compile_definitions(${PROJECT_NAME} PRIVATE OPENPGL_RADIANCE_CACHES) endif() +if(OPENPGL_EF_VSP_GUIDING) +target_compile_definitions(${PROJECT_NAME} PRIVATE OPENPGL_VSP_GUIDING) +endif() + + if(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER) target_compile_definitions(${PROJECT_NAME} PRIVATE OPENPGL_IMAGE_SPACE_GUIDING_BUFFER) endif() @@ -235,6 +240,11 @@ if(OPENPGL_EF_RADIANCE_CACHES) set(OPENPGL_RADIANCE_CACHES ON) endif() +if(OPENPGL_EF_VSP_GUIDING) + set(OPENPGL_VSP_GUIDING ON) +endif() + + if(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER) set(OPENPGL_IMAGE_SPACE_GUIDING_BUFFER ON) endif() diff --git a/openpgl/api/api.cpp b/openpgl/api/api.cpp index e1c19320..55644f08 100644 --- a/openpgl/api/api.cpp +++ b/openpgl/api/api.cpp @@ -609,12 +609,14 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglSurfaceSamplingDistributionGetId(PGLSur return gSurfaceSamplingDistribution->getId(); } +#ifdef OPENPGL_VSP_GUIDING extern "C" OPENPGL_DLLEXPORT float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, bool contributionBased) { ISurfaceSamplingDistribution *gSurfaceSamplingDistribution = (ISurfaceSamplingDistribution *)surfaceSamplingDistribution; return gSurfaceSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); } +#endif extern "C" OPENPGL_DLLEXPORT bool pglSurfaceSamplingDistributionValidate(PGLSurfaceSamplingDistribution surfaceSamplingDistribution) { @@ -714,12 +716,14 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglVolumeSamplingDistributionGetId(PGLVolu return gVolumeSamplingDistribution->getId(); } +#ifdef OPENPGL_VSP_GUIDING extern "C" OPENPGL_DLLEXPORT float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution volumeSamplingDistribution, pgl_vec3f direction, bool contributionBased) { IVolumeSamplingDistribution *gVolumeSamplingDistribution = (IVolumeSamplingDistribution *)volumeSamplingDistribution; return gVolumeSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); } +#endif extern "C" OPENPGL_DLLEXPORT bool pglVolumeSamplingDistributionValidate(PGLVolumeSamplingDistribution volumeSamplingDistribution) { diff --git a/openpgl/directional/ISurfaceSamplingDistribution.h b/openpgl/directional/ISurfaceSamplingDistribution.h index f67be895..f78ef3ac 100644 --- a/openpgl/directional/ISurfaceSamplingDistribution.h +++ b/openpgl/directional/ISurfaceSamplingDistribution.h @@ -57,7 +57,9 @@ struct ISurfaceSamplingDistribution virtual const IRegion *getRegion() const = 0; +#ifdef OPENPGL_VSP_GUIDING virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; +#endif protected: // const IRegion* m_region {nullptr}; diff --git a/openpgl/directional/IVolumeSamplingDistribution.h b/openpgl/directional/IVolumeSamplingDistribution.h index 0bc20602..6b9bbaaf 100644 --- a/openpgl/directional/IVolumeSamplingDistribution.h +++ b/openpgl/directional/IVolumeSamplingDistribution.h @@ -59,7 +59,9 @@ struct IVolumeSamplingDistribution virtual const IRegion *getRegion() const = 0; +#ifdef OPENPGL_VSP_GUIDING virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; +#endif protected: // const IRegion* m_region {nullptr}; diff --git a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h index e118bf7b..6a2eaebd 100644 --- a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h @@ -87,10 +87,12 @@ struct DQTSurfaceSamplingDistribution : public ISurfaceSamplingDistribution m_region = region; } +#ifdef OPENPGL_VSP_GUIDING float volumeScatterProbability(Vector3 dir, bool contributionBased) const override { return 0.f; } +#endif private: TDirectionalQuadtree distribution; diff --git a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h index fc0c72f0..8b743496 100644 --- a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h @@ -93,10 +93,12 @@ struct DQTVolumeSamplingDistribution : public IVolumeSamplingDistribution m_region = region; } +#ifdef OPENPGL_VSP_GUIDING float volumeScatterProbability(Vector3 dir, bool contributionBased) const override { return 0.f; } +#endif private: TDirectionalQuadtree distribution; diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h index 03a71711..7d94292f 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h @@ -76,8 +76,10 @@ struct ParallaxAwareVonMisesFisherMixture embree::vfloat _distances[NumVectors]; Point3 _pivotPosition{0.0f, 0.0f, 0.0f}; +#ifdef OPENPGL_VSP_GUIDING embree::vfloat _volumeScatterFirstMomentProbabilityWeights[NumVectors]; embree::vfloat _volumeScatterSecondMomentProbabilityWeights[NumVectors]; +#endif #ifdef OPENPGL_RADIANCE_CACHES // fluence attributes @@ -159,7 +161,9 @@ struct ParallaxAwareVonMisesFisherMixture bool isValid() const; +#ifdef OPENPGL_VSP_GUIDING float volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const; +#endif std::string toString() const; @@ -256,8 +260,10 @@ std::string ParallaxAwareVonMisesFisherMixture_eMinus2Kappa[tmp.quot][tmp.rem]; ss << "\t meanCosine: " << this->_meanCosines[tmp.quot][tmp.rem]; ss << "\t distance: " << _distances[tmp.quot][tmp.rem]; +#ifdef OPENPGL_VSP_GUIDING ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterFirstMomentProbabilityWeights[tmp.quot][tmp.rem]; ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterSecondMomentProbabilityWeights[tmp.quot][tmp.rem]; +#endif #ifdef OPENPGL_RADIANCE_CACHES ss << "\t fluenceRGBWeightWithMIS: " << _fluenceRGBWeightsWithMIS[tmp.quot].x[tmp.rem] << "\t" << _fluenceRGBWeightsWithMIS[tmp.quot].y[tmp.rem] << "\t" << _fluenceRGBWeightsWithMIS[tmp.quot].z[tmp.rem]; @@ -306,8 +312,10 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeightsWithMIS); serializeVec3Vectors(stream, _fluenceRGBWeights); #endif +#ifdef OPENPGL_VSP_GUIDING serializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); serializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); - +#endif stream.write(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.write(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -557,9 +571,10 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeightsWithMIS); deserializeVec3Vectors(stream, _fluenceRGBWeights); #endif +#ifdef OPENPGL_VSP_GUIDING deserializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); deserializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); - +#endif stream.read(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.read(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -621,7 +636,7 @@ bool ParallaxAwareVonMisesFisherMixture= 0.0f; OPENPGL_ASSERT(valid); - +#ifdef OPENPGL_VSP_GUIDING valid = valid && embree::isvalid(_volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem]); valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; @@ -631,6 +646,7 @@ bool ParallaxAwareVonMisesFisherMixture= 0.0f; valid = valid && _volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; OPENPGL_ASSERT(valid); +#endif } // check unused componets @@ -672,7 +688,7 @@ bool ParallaxAwareVonMisesFisherMixture float ParallaxAwareVonMisesFisherMixture::volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const { @@ -1275,7 +1293,7 @@ float ParallaxAwareVonMisesFisherMixture Vector3 ParallaxAwareVonMisesFisherMixture::incomingRadiance(const Vector3 &direction, const bool directLightMIS) const diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h index 986eedb9..5f811127 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h @@ -96,14 +96,14 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory public: embree::Vec3 > sumOfWeightedDirections[VMM::NumVectors]; embree::vfloat sumOfWeightedStats[VMM::NumVectors]; - +#ifdef OPENPGL_VSP_GUIDING embree::vfloat volumeContributionFirstMomentWeights[VMM::NumVectors]; embree::vfloat surfaceContributionFirstMomentWeights[VMM::NumVectors]; embree::vfloat volumeContributionSecondMomentWeights[VMM::NumVectors]; embree::vfloat surfaceContributionSecondMomentWeights[VMM::NumVectors]; embree::vfloat volumeSampleNumberWeights[VMM::NumVectors]; embree::vfloat surfaceSampleNumberWeights[VMM::NumVectors]; - +#endif float sumWeights{0.f}; float numSamples{0.f}; float overallNumSamples{0.f}; @@ -211,8 +211,9 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory void updateComponentDistances(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; +#ifdef OPENPGL_VSP_GUIDING void updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; - +#endif private: void _initUniformDirections(); @@ -324,6 +325,7 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && sumOfDistanceWeightes[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); +#ifdef OPENPGL_VSP_GUIDING valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); @@ -347,6 +349,7 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && embree::isvalid(surfaceSampleNumberWeights[tmpK.quot][tmpK.rem]); valid = valid && surfaceSampleNumberWeights[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); +#endif } for (size_t k = numComponents; k < VMM::MaxComponents; k++) @@ -368,6 +371,7 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && sumOfDistanceWeightes[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); +#ifdef OPENPGL_VSP_GUIDING valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); @@ -391,6 +395,7 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS valid = valid && embree::isvalid(surfaceSampleNumberWeights[tmpK.quot][tmpK.rem]); valid = valid && surfaceSampleNumberWeights[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); +#endif } valid = valid && embree::isvalid(numSamples); @@ -415,12 +420,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.write(reinterpret_cast(&overallNumSamples), sizeof(float)); stream.write(reinterpret_cast(&numComponents), sizeof(size_t)); stream.write(reinterpret_cast(&normalized), sizeof(bool)); +#ifdef OPENPGL_VSP_GUIDING serializeFloatVectors(stream, volumeContributionFirstMomentWeights); serializeFloatVectors(stream, surfaceContributionFirstMomentWeights); serializeFloatVectors(stream, volumeContributionSecondMomentWeights); serializeFloatVectors(stream, surfaceContributionSecondMomentWeights); serializeFloatVectors(stream, volumeSampleNumberWeights); serializeFloatVectors(stream, surfaceSampleNumberWeights); +#endif } template @@ -434,12 +441,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.read(reinterpret_cast(&overallNumSamples), sizeof(float)); stream.read(reinterpret_cast(&numComponents), sizeof(size_t)); stream.read(reinterpret_cast(&normalized), sizeof(bool)); +#ifdef OPENPGL_VSP_GUIDING deserializeFloatVectors(stream, volumeContributionFirstMomentWeights); deserializeFloatVectors(stream, surfaceContributionFirstMomentWeights); deserializeFloatVectors(stream, volumeContributionSecondMomentWeights); deserializeFloatVectors(stream, surfaceContributionSecondMomentWeights); deserializeFloatVectors(stream, volumeSampleNumberWeights); deserializeFloatVectors(stream, surfaceSampleNumberWeights); +#endif } template @@ -457,13 +466,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[k] = zeros; sumOfDistanceWeightes[k] = zeros; - +#ifdef OPENPGL_VSP_GUIDING volumeContributionFirstMomentWeights[k] = 0.0f; surfaceContributionFirstMomentWeights[k] = 0.0f; volumeContributionSecondMomentWeights[k] = 0.0f; surfaceContributionSecondMomentWeights[k] = 0.0f; volumeSampleNumberWeights[k] = 0.0f; surfaceSampleNumberWeights[k] = 0.0f; +#endif } sumWeights = 0.0f; @@ -482,13 +492,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[tmpIdx.quot][tmpIdx.rem] = 0.f; sumOfDistanceWeightes[tmpIdx.quot][tmpIdx.rem] = 0.f; - +#ifdef OPENPGL_VSP_GUIDING volumeContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; surfaceContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; volumeContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; surfaceContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; volumeSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; surfaceSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; +#endif } template @@ -508,13 +519,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[k] *= alpha; sumOfDistanceWeightes[k] *= alpha; - +#ifdef OPENPGL_VSP_GUIDING volumeContributionFirstMomentWeights[k] *= alpha; surfaceContributionFirstMomentWeights[k] *= alpha; volumeContributionSecondMomentWeights[k] *= alpha; surfaceContributionSecondMomentWeights[k] *= alpha; volumeSampleNumberWeights[k] *= alpha; surfaceSampleNumberWeights[k] *= alpha; +#endif } numSamples *= alpha; @@ -576,13 +588,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS std::swap(sumOfWeightedDirections[tmpIdx0.quot].z[tmpIdx0.rem], sumOfWeightedDirections[tmpIdx1.quot].z[tmpIdx1.rem]); std::swap(sumOfWeightedStats[tmpIdx0.quot][tmpIdx0.rem], sumOfWeightedStats[tmpIdx1.quot][tmpIdx1.rem]); std::swap(sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem], sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]); - +#ifdef OPENPGL_VSP_GUIDING std::swap(volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); +#endif } template @@ -590,7 +603,6 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS { const div_t tmpIdx0 = div(idx0, VMM::VectorSize); const div_t tmpIdx1 = div(idx1, VMM::VectorSize); - const div_t tmpIdx2 = div(numComponents - 1, VMM::VectorSize); // merging the statistics of the component 0 and 1 sumOfWeightedDirections[tmpIdx0.quot].x[tmpIdx0.rem] += sumOfWeightedDirections[tmpIdx1.quot].x[tmpIdx1.rem]; @@ -599,14 +611,14 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfWeightedStats[tmpIdx0.quot][tmpIdx0.rem] += sumOfWeightedStats[tmpIdx1.quot][tmpIdx1.rem]; sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem] += sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]; - // copying the statistics of the last component to the position of component 1 +#ifdef OPENPGL_VSP_GUIDING volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; - +#endif swapComponentStats(idx1, numComponents - 1); clearComponentStats(numComponents - 1); @@ -643,9 +655,9 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[tmpI.quot][tmpI.rem] = tmp; sumOfDistanceWeightes[tmpJ.quot][tmpJ.rem] = tmp; +#ifdef OPENPGL_VSP_GUIDING float weight0 = 0.5f; float weight1 = 0.5f; - volumeContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem] *= weight0; surfaceContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; @@ -658,7 +670,7 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS volumeSampleNumberWeights[tmpI.quot][tmpI.rem] *= weight0; surfaceSampleNumberWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceSampleNumberWeights[tmpI.quot][tmpI.rem]; surfaceSampleNumberWeights[tmpI.quot][tmpI.rem] *= weight0; - +#endif numComponents += 1; OPENPGL_ASSERT(!std::isnan(sumOfWeightedDirections[tmpI.quot].x[tmpI.rem]) && std::isfinite(sumOfWeightedDirections[tmpI.quot].x[tmpI.rem])); @@ -1740,6 +1752,7 @@ std::string ParallaxAwareVonMisesFisherWeightedEMFactory::Part return ss.str(); } +#ifdef OPENPGL_VSP_GUIDING template void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const @@ -1852,5 +1865,5 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum } } } - +#endif } // namespace openpgl diff --git a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h index e81a7a6c..e484da5a 100644 --- a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h @@ -156,10 +156,12 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMSurfaceSamplingDistributio m_region = region; } +#ifdef OPENPGL_VSP_GUIDING float volumeScatterProbability(Vector3 dir, bool contributionBased) const override { return m_liDistribution.volumeScatterProbability(dir, contributionBased); } +#endif }; } // namespace openpgl \ No newline at end of file diff --git a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h index 82371331..0350c9d9 100644 --- a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h @@ -188,10 +188,12 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMVolumeSamplingDistribution m_region = region; } +#ifdef OPENPGL_VSP_GUIDING float volumeScatterProbability(Vector3 dir, bool contributionBased) const override { return m_liDistribution.volumeScatterProbability(dir, contributionBased); } +#endif }; } // namespace openpgl \ No newline at end of file diff --git a/openpgl/field/Field.h b/openpgl/field/Field.h index 1d61f0c7..10e55306 100644 --- a/openpgl/field/Field.h +++ b/openpgl/field/Field.h @@ -462,9 +462,11 @@ struct Field zeroValueSamples.data() + regionStorage.second.m_is_begin, regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif +#ifdef OPENPGL_VSP_GUIDING m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, regionStorage.second.m_end - regionStorage.second.m_begin); +#endif // TODO: we should move setting the pivot to the factory regionStorage.first.distribution._pivotPosition = sampleMean; regionStorage.first.valid = regionStorage.first.distribution.isValid(); @@ -540,7 +542,6 @@ struct Field OPENPGL_ASSERT(regionStorage.first.trainingStatistics.sufficientStatistics.isValid()); } typename DirectionalDistributionFactory::FittingStatistics fittingStats; - float numSamples = regionStorage.first.trainingStatistics.getNumSamples(); m_distributionFactory.prepareSamples(samples.data() + regionStorage.second.m_begin, regionStorage.second.m_end - regionStorage.second.m_begin, regionStorage.first.sampleStatistics, m_distributionFactorySettings); if (regionStorage.first.initialized) @@ -562,9 +563,11 @@ struct Field zeroValueSamples.data() + regionStorage.second.m_is_begin, regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif +#ifdef OPENPGL_VSP_GUIDING m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, regionStorage.second.m_end - regionStorage.second.m_begin); +#endif regionStorage.first.valid = regionStorage.first.isValid(); #ifdef OPENPGL_DEBUG_MODE if (!regionStorage.first.valid) diff --git a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h index ae7da55b..5157a493 100644 --- a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h @@ -147,7 +147,9 @@ struct SurfaceSamplingDistribution pgl_vec3f Irradiance(pgl_vec3f &normal, const bool directLightMIS) const; #endif +#ifdef OPENPGL_VSP_GUIDING float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; +#endif /////////////////////////////////////// /// Future plans /////////////////////////////////////// @@ -288,11 +290,12 @@ OPENPGL_INLINE pgl_vec3f SurfaceSamplingDistribution::Irradiance(pgl_vec3f &norm } #endif +#ifdef OPENPGL_VSP_GUIDING OPENPGL_INLINE float SurfaceSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const { OPENPGL_ASSERT(m_surfaceSamplingDistributionHandle); return pglSurfaceSamplingDistributionVolumeScatterProbability(m_surfaceSamplingDistributionHandle, direction, contributionBased); } - +#endif } // namespace cpp } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h index ce49fa80..b369f563 100644 --- a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h @@ -164,7 +164,9 @@ struct VolumeSamplingDistribution pgl_vec3f Fluence(const bool directLightMIS) const; #endif +#ifdef OPENPGL_VSP_GUIDING float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; +#endif /////////////////////////////////////// /// Future plans /////////////////////////////////////// @@ -309,11 +311,13 @@ OPENPGL_INLINE pgl_vec3f VolumeSamplingDistribution::Fluence(const bool directLi } #endif +#ifdef OPENPGL_VSP_GUIDING OPENPGL_INLINE float VolumeSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const { OPENPGL_ASSERT(m_volumeSamplingDistributionHandle); return pglVolumeSamplingDistributionVolumeScatterProbability(m_volumeSamplingDistributionHandle, direction, contributionBased); } +#endif } // namespace cpp } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/defines.h.in b/openpgl/include/openpgl/defines.h.in index 8732b4b9..cf28e8b5 100644 --- a/openpgl/include/openpgl/defines.h.in +++ b/openpgl/include/openpgl/defines.h.in @@ -5,6 +5,7 @@ #cmakedefine OPENPGL_SUPPORT_DEVICE_TYPE_CPU_16 #cmakedefine OPENPGL_RADIANCE_CACHES +#cmakedefine OPENPGL_VSP_GUIDING #cmakedefine OPENPGL_IMAGE_SPACE_GUIDING_BUFFER #cmakedefine OPENPGL_DIRECTION_COMPRESSION #cmakedefine OPENPGL_RADIANCE_COMPRESSION \ No newline at end of file diff --git a/openpgl/include/openpgl/surfacesamplingdistribution.h b/openpgl/include/openpgl/surfacesamplingdistribution.h index bdc166fe..b3aee911 100644 --- a/openpgl/include/openpgl/surfacesamplingdistribution.h +++ b/openpgl/include/openpgl/surfacesamplingdistribution.h @@ -51,8 +51,10 @@ typedef ManagedObject SurfaceSamplingDistribution; OPENPGL_CORE_INTERFACE pgl_vec3f pglSurfaceSamplingDistributionOutgoingRadiance(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction); #endif +#ifdef OPENPGL_VSP_GUIDING OPENPGL_CORE_INTERFACE float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, bool contributionBased); +#endif #ifdef __cplusplus } // extern "C" diff --git a/openpgl/include/openpgl/volumesamplingdistribution.h b/openpgl/include/openpgl/volumesamplingdistribution.h index c634e5dd..5665c890 100644 --- a/openpgl/include/openpgl/volumesamplingdistribution.h +++ b/openpgl/include/openpgl/volumesamplingdistribution.h @@ -54,9 +54,10 @@ typedef ManagedObject VolumeSamplingDistribution; OPENPGL_CORE_INTERFACE pgl_vec3f pglVolumeSamplingDistributionFluence(PGLVolumeSamplingDistribution volumeSamplingDistribution, const bool directLightMIS); #endif +#ifdef OPENPGL_VSP_GUIDING OPENPGL_CORE_INTERFACE float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution VolumeSamplingDistribution, pgl_vec3f direction, bool contributionBased); - +#endif #ifdef __cplusplus } // extern "C" #endif \ No newline at end of file From 2ace04e07c1eb910dbb73afe4b8ca8a967c6723f Mon Sep 17 00:00:00 2001 From: "Herholz, Sebastian" Date: Fri, 16 Aug 2024 16:00:52 +0200 Subject: [PATCH 03/15] [vsp] Only learn one VSP value; contribution (default) or variance based). The type can be configured using FieldConfig::SetVarianceBasedVSP() --- openpgl/api/api.cpp | 10 +- openpgl/device/Device.h | 9 + .../ISurfaceSamplingDistribution.h | 2 +- .../directional/IVolumeSamplingDistribution.h | 2 +- openpgl/directional/dqt/DQTFactory.h | 2 +- .../dqt/DQTSurfaceSamplingDistribution.h | 2 +- .../dqt/DQTVolumeSamplingDistribution.h | 2 +- .../vmm/AdaptiveSplitandMergeFactory.h | 6 +- .../vmm/ParallaxAwareVonMisesFisherMixture.h | 66 ++---- ...llaxAwareVonMisesFisherWeightedEMFactory.h | 191 ++++++++---------- .../vmm/VMMSurfaceSamplingDistribution.h | 4 +- .../vmm/VMMVolumeSamplingDistribution.h | 4 +- openpgl/field/Field.h | 21 +- openpgl/include/openpgl/config.h | 3 + openpgl/include/openpgl/cpp/FieldConfig.h | 9 + .../openpgl/cpp/SurfaceSamplingDistribution.h | 6 +- .../openpgl/cpp/VolumeSamplingDistribution.h | 6 +- .../openpgl/surfacesamplingdistribution.h | 3 +- .../openpgl/volumesamplingdistribution.h | 3 +- 19 files changed, 165 insertions(+), 186 deletions(-) diff --git a/openpgl/api/api.cpp b/openpgl/api/api.cpp index 55644f08..805d68d9 100644 --- a/openpgl/api/api.cpp +++ b/openpgl/api/api.cpp @@ -610,11 +610,10 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglSurfaceSamplingDistributionGetId(PGLSur } #ifdef OPENPGL_VSP_GUIDING -extern "C" OPENPGL_DLLEXPORT float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, - bool contributionBased) +extern "C" OPENPGL_DLLEXPORT float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction) { ISurfaceSamplingDistribution *gSurfaceSamplingDistribution = (ISurfaceSamplingDistribution *)surfaceSamplingDistribution; - return gSurfaceSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); + return gSurfaceSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z)); } #endif @@ -717,11 +716,10 @@ extern "C" OPENPGL_DLLEXPORT uint32_t pglVolumeSamplingDistributionGetId(PGLVolu } #ifdef OPENPGL_VSP_GUIDING -extern "C" OPENPGL_DLLEXPORT float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution volumeSamplingDistribution, pgl_vec3f direction, - bool contributionBased) +extern "C" OPENPGL_DLLEXPORT float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution volumeSamplingDistribution, pgl_vec3f direction) { IVolumeSamplingDistribution *gVolumeSamplingDistribution = (IVolumeSamplingDistribution *)volumeSamplingDistribution; - return gVolumeSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z), contributionBased); + return gVolumeSamplingDistribution->volumeScatterProbability(openpgl::Vector3(direction.x, direction.y, direction.z)); } #endif diff --git a/openpgl/device/Device.h b/openpgl/device/Device.h index 01bcbc96..a8c75bee 100644 --- a/openpgl/device/Device.h +++ b/openpgl/device/Device.h @@ -99,6 +99,9 @@ struct Device : public IDevice typename GuidingField::Settings gFieldSettings; gFieldSettings.settings.decayOnSpatialSplit = 0.25f; gFieldSettings.settings.deterministic = args.deterministic; +#ifdef OPENPGL_VSP_GUIDING + gFieldSettings.settings.varianceBasedVSP = args.varianceBasedVSP; +#endif gFieldSettings.debugSettings.fitRegions = args.debugArguments.fitRegions; PGLKDTreeArguments *spatialSturctureArguments = (PGLKDTreeArguments *)args.spatialSturctureArguments; @@ -148,6 +151,9 @@ struct Device : public IDevice typename GuidingField::Settings gFieldSettings; gFieldSettings.settings.decayOnSpatialSplit = 0.25f; gFieldSettings.settings.deterministic = args.deterministic; +#ifdef OPENPGL_VSP_GUIDING + gFieldSettings.settings.varianceBasedVSP = args.varianceBasedVSP; +#endif gFieldSettings.debugSettings.fitRegions = args.debugArguments.fitRegions; PGLKDTreeArguments *spatialSturctureArguments = (PGLKDTreeArguments *)args.spatialSturctureArguments; @@ -197,6 +203,9 @@ struct Device : public IDevice typename GuidingField::Settings gFieldSettings; gFieldSettings.settings.decayOnSpatialSplit = 0.25f; gFieldSettings.settings.deterministic = args.deterministic; +#ifdef OPENPGL_VSP_GUIDING + gFieldSettings.settings.varianceBasedVSP = args.varianceBasedVSP; +#endif gFieldSettings.debugSettings.fitRegions = args.debugArguments.fitRegions; PGLKDTreeArguments *spatialSturctureArguments = (PGLKDTreeArguments *)args.spatialSturctureArguments; diff --git a/openpgl/directional/ISurfaceSamplingDistribution.h b/openpgl/directional/ISurfaceSamplingDistribution.h index f78ef3ac..99773619 100644 --- a/openpgl/directional/ISurfaceSamplingDistribution.h +++ b/openpgl/directional/ISurfaceSamplingDistribution.h @@ -58,7 +58,7 @@ struct ISurfaceSamplingDistribution virtual const IRegion *getRegion() const = 0; #ifdef OPENPGL_VSP_GUIDING - virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; + virtual float volumeScatterProbability(Vector3 dir) const = 0; #endif protected: diff --git a/openpgl/directional/IVolumeSamplingDistribution.h b/openpgl/directional/IVolumeSamplingDistribution.h index 6b9bbaaf..32785996 100644 --- a/openpgl/directional/IVolumeSamplingDistribution.h +++ b/openpgl/directional/IVolumeSamplingDistribution.h @@ -60,7 +60,7 @@ struct IVolumeSamplingDistribution virtual const IRegion *getRegion() const = 0; #ifdef OPENPGL_VSP_GUIDING - virtual float volumeScatterProbability(Vector3 dir, bool contributionBased) const = 0; + virtual float volumeScatterProbability(Vector3 dir) const = 0; #endif protected: diff --git a/openpgl/directional/dqt/DQTFactory.h b/openpgl/directional/dqt/DQTFactory.h index 07b5c095..fce46734 100644 --- a/openpgl/directional/dqt/DQTFactory.h +++ b/openpgl/directional/dqt/DQTFactory.h @@ -180,7 +180,7 @@ class DirectionalQuadtreeFactory const SampleStatistics &sampleStatistics) const {} - void updateVolumeScatterProbability(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples) const {} + void updateVolumeScatterProbability(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const {} void fit(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const Configuration &cfg, FittingStatistics &fitStats) { diff --git a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h index 6a2eaebd..390da1ea 100644 --- a/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTSurfaceSamplingDistribution.h @@ -88,7 +88,7 @@ struct DQTSurfaceSamplingDistribution : public ISurfaceSamplingDistribution } #ifdef OPENPGL_VSP_GUIDING - float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + float volumeScatterProbability(Vector3 dir) const override { return 0.f; } diff --git a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h index 8b743496..c0cc5bf8 100644 --- a/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h +++ b/openpgl/directional/dqt/DQTVolumeSamplingDistribution.h @@ -94,7 +94,7 @@ struct DQTVolumeSamplingDistribution : public IVolumeSamplingDistribution } #ifdef OPENPGL_VSP_GUIDING - float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + float volumeScatterProbability(Vector3 dir) const override { return 0.f; } diff --git a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h index 2bb92b4a..ef610848 100644 --- a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h +++ b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h @@ -126,7 +126,7 @@ struct AdaptiveSplitAndMergeFactory void updateFluenceEstimate(VMM &vmm, const SampleData *samples, const size_t numSamples, const size_t numZeroValueSamples, const SampleStatistics &sampleStatistics) const; - void updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples) const; + void updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const; std::string toString() const { @@ -470,10 +470,10 @@ void AdaptiveSplitAndMergeFactory::updateFluenceEstimate(VMM & } template -void AdaptiveSplitAndMergeFactory::updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples) const +void AdaptiveSplitAndMergeFactory::updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const { WeightedEMFactory factory = WeightedEMFactory(); - factory.updateVolumeScatterProbability(vmm, stats.sufficientStatistics, samples, numSamples); + factory.updateVolumeScatterProbability(vmm, stats.sufficientStatistics, samples, numSamples, varianceBased); } } // namespace openpgl diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h index 7d94292f..144aa631 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h @@ -77,8 +77,7 @@ struct ParallaxAwareVonMisesFisherMixture Point3 _pivotPosition{0.0f, 0.0f, 0.0f}; #ifdef OPENPGL_VSP_GUIDING - embree::vfloat _volumeScatterFirstMomentProbabilityWeights[NumVectors]; - embree::vfloat _volumeScatterSecondMomentProbabilityWeights[NumVectors]; + embree::vfloat _volumeScatterProbabilityWeights[NumVectors]; #endif #ifdef OPENPGL_RADIANCE_CACHES @@ -162,7 +161,7 @@ struct ParallaxAwareVonMisesFisherMixture bool isValid() const; #ifdef OPENPGL_VSP_GUIDING - float volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const; + float volumeScatterProbability(const Vector3 &direction) const; #endif std::string toString() const; @@ -261,8 +260,7 @@ std::string ParallaxAwareVonMisesFisherMixture_meanCosines[tmp.quot][tmp.rem]; ss << "\t distance: " << _distances[tmp.quot][tmp.rem]; #ifdef OPENPGL_VSP_GUIDING - ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterFirstMomentProbabilityWeights[tmp.quot][tmp.rem]; - ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterSecondMomentProbabilityWeights[tmp.quot][tmp.rem]; + ss << "\t volumeScatterProbabilityWeight: " << _volumeScatterProbabilityWeights[tmp.quot][tmp.rem]; #endif #ifdef OPENPGL_RADIANCE_CACHES ss << "\t fluenceRGBWeightWithMIS: " << _fluenceRGBWeightsWithMIS[tmp.quot].x[tmp.rem] << "\t" << _fluenceRGBWeightsWithMIS[tmp.quot].y[tmp.rem] << "\t" @@ -313,8 +311,7 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeights); #endif #ifdef OPENPGL_VSP_GUIDING - serializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); - serializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); + serializeFloatVectors(stream, _volumeScatterProbabilityWeights); #endif stream.write(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.write(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -572,8 +561,7 @@ void ParallaxAwareVonMisesFisherMixture(stream, _fluenceRGBWeights); #endif #ifdef OPENPGL_VSP_GUIDING - deserializeFloatVectors(stream, _volumeScatterFirstMomentProbabilityWeights); - deserializeFloatVectors(stream, _volumeScatterSecondMomentProbabilityWeights); + deserializeFloatVectors(stream, _volumeScatterProbabilityWeights); #endif stream.read(reinterpret_cast(&_numComponents), sizeof(_numComponents)); stream.read(reinterpret_cast(&_pivotPosition), sizeof(Point3)); @@ -637,14 +625,9 @@ bool ParallaxAwareVonMisesFisherMixture= 0.0f; OPENPGL_ASSERT(valid); #ifdef OPENPGL_VSP_GUIDING - valid = valid && embree::isvalid(_volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem]); - valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; - valid = valid && _volumeScatterFirstMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; - OPENPGL_ASSERT(valid); - - valid = valid && embree::isvalid(_volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem]); - valid = valid && _volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; - valid = valid && _volumeScatterSecondMomentProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; + valid = valid && embree::isvalid(_volumeScatterProbabilityWeights[tmpK.quot][tmpK.rem]); + valid = valid && _volumeScatterProbabilityWeights[tmpK.quot][tmpK.rem] >= 0.0f; + valid = valid && _volumeScatterProbabilityWeights[tmpK.quot][tmpK.rem] <= 1.0f; OPENPGL_ASSERT(valid); #endif } @@ -689,12 +672,8 @@ bool ParallaxAwareVonMisesFisherMixture -float ParallaxAwareVonMisesFisherMixture::volumeScatterProbability(const Vector3 &direction, const bool contributionBased) const +float ParallaxAwareVonMisesFisherMixture::volumeScatterProbability(const Vector3 &direction) const { const int cnt = (_numComponents + VecSize - 1) / VecSize; @@ -1281,14 +1260,7 @@ float ParallaxAwareVonMisesFisherMixture cosThetaMinusOne = embree::min(cosTheta - ones, zeros); const embree::vfloat eval = _weights[k] * _normalizations[k] * embree::fastapprox::exp>(_kappas[k] * cosThetaMinusOne); pdf += eval; - if (contributionBased) - { - volumeScatterProbability += _volumeScatterFirstMomentProbabilityWeights[k] * eval; - } - else - { - volumeScatterProbability += _volumeScatterSecondMomentProbabilityWeights[k] * eval; - } + volumeScatterProbability += _volumeScatterProbabilityWeights[k] * eval; } return reduce_add(volumeScatterProbability) / reduce_add(pdf); diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h index 5f811127..accd0478 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherWeightedEMFactory.h @@ -97,10 +97,8 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory embree::Vec3 > sumOfWeightedDirections[VMM::NumVectors]; embree::vfloat sumOfWeightedStats[VMM::NumVectors]; #ifdef OPENPGL_VSP_GUIDING - embree::vfloat volumeContributionFirstMomentWeights[VMM::NumVectors]; - embree::vfloat surfaceContributionFirstMomentWeights[VMM::NumVectors]; - embree::vfloat volumeContributionSecondMomentWeights[VMM::NumVectors]; - embree::vfloat surfaceContributionSecondMomentWeights[VMM::NumVectors]; + embree::vfloat volumeContributionWeights[VMM::NumVectors]; + embree::vfloat surfaceContributionWeights[VMM::NumVectors]; embree::vfloat volumeSampleNumberWeights[VMM::NumVectors]; embree::vfloat surfaceSampleNumberWeights[VMM::NumVectors]; #endif @@ -212,7 +210,7 @@ struct ParallaxAwareVonMisesFisherWeightedEMFactory void updateComponentDistances(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; #ifdef OPENPGL_VSP_GUIDING - void updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples) const; + void updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const; #endif private: void _initUniformDirections(); @@ -326,20 +324,12 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS OPENPGL_ASSERT(valid); #ifdef OPENPGL_VSP_GUIDING - valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + valid = valid && embree::isvalid(volumeContributionWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionWeights[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); - valid = valid && embree::isvalid(surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; - OPENPGL_ASSERT(valid); - - valid = valid && embree::isvalid(volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; - OPENPGL_ASSERT(valid); - - valid = valid && embree::isvalid(surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem] >= 0.0f; + valid = valid && embree::isvalid(surfaceContributionWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionWeights[tmpK.quot][tmpK.rem] >= 0.0f; OPENPGL_ASSERT(valid); valid = valid && embree::isvalid(volumeSampleNumberWeights[tmpK.quot][tmpK.rem]); @@ -372,20 +362,12 @@ bool ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS OPENPGL_ASSERT(valid); #ifdef OPENPGL_VSP_GUIDING - valid = valid && embree::isvalid(volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && volumeContributionFirstMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; - OPENPGL_ASSERT(valid); - - valid = valid && embree::isvalid(surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && surfaceContributionFirstMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + valid = valid && embree::isvalid(volumeContributionWeights[tmpK.quot][tmpK.rem]); + valid = valid && volumeContributionWeights[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); - valid = valid && embree::isvalid(volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && volumeContributionSecondMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; - OPENPGL_ASSERT(valid); - - valid = valid && embree::isvalid(surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem]); - valid = valid && surfaceContributionSecondMomentWeights[tmpK.quot][tmpK.rem] == 0.0f; + valid = valid && embree::isvalid(surfaceContributionWeights[tmpK.quot][tmpK.rem]); + valid = valid && surfaceContributionWeights[tmpK.quot][tmpK.rem] == 0.0f; OPENPGL_ASSERT(valid); valid = valid && embree::isvalid(volumeSampleNumberWeights[tmpK.quot][tmpK.rem]); @@ -421,10 +403,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.write(reinterpret_cast(&numComponents), sizeof(size_t)); stream.write(reinterpret_cast(&normalized), sizeof(bool)); #ifdef OPENPGL_VSP_GUIDING - serializeFloatVectors(stream, volumeContributionFirstMomentWeights); - serializeFloatVectors(stream, surfaceContributionFirstMomentWeights); - serializeFloatVectors(stream, volumeContributionSecondMomentWeights); - serializeFloatVectors(stream, surfaceContributionSecondMomentWeights); + serializeFloatVectors(stream, volumeContributionWeights); + serializeFloatVectors(stream, surfaceContributionWeights); serializeFloatVectors(stream, volumeSampleNumberWeights); serializeFloatVectors(stream, surfaceSampleNumberWeights); #endif @@ -442,10 +422,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS stream.read(reinterpret_cast(&numComponents), sizeof(size_t)); stream.read(reinterpret_cast(&normalized), sizeof(bool)); #ifdef OPENPGL_VSP_GUIDING - deserializeFloatVectors(stream, volumeContributionFirstMomentWeights); - deserializeFloatVectors(stream, surfaceContributionFirstMomentWeights); - deserializeFloatVectors(stream, volumeContributionSecondMomentWeights); - deserializeFloatVectors(stream, surfaceContributionSecondMomentWeights); + deserializeFloatVectors(stream, volumeContributionWeights); + deserializeFloatVectors(stream, surfaceContributionWeights); deserializeFloatVectors(stream, volumeSampleNumberWeights); deserializeFloatVectors(stream, surfaceSampleNumberWeights); #endif @@ -467,10 +445,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[k] = zeros; #ifdef OPENPGL_VSP_GUIDING - volumeContributionFirstMomentWeights[k] = 0.0f; - surfaceContributionFirstMomentWeights[k] = 0.0f; - volumeContributionSecondMomentWeights[k] = 0.0f; - surfaceContributionSecondMomentWeights[k] = 0.0f; + volumeContributionWeights[k] = 0.0f; + surfaceContributionWeights[k] = 0.0f; volumeSampleNumberWeights[k] = 0.0f; surfaceSampleNumberWeights[k] = 0.0f; #endif @@ -493,10 +469,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[tmpIdx.quot][tmpIdx.rem] = 0.f; #ifdef OPENPGL_VSP_GUIDING - volumeContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; - surfaceContributionFirstMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; - volumeContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; - surfaceContributionSecondMomentWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + volumeContributionWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; + surfaceContributionWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; volumeSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; surfaceSampleNumberWeights[tmpIdx.quot][tmpIdx.rem] = 0.f; #endif @@ -520,10 +494,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[k] *= alpha; #ifdef OPENPGL_VSP_GUIDING - volumeContributionFirstMomentWeights[k] *= alpha; - surfaceContributionFirstMomentWeights[k] *= alpha; - volumeContributionSecondMomentWeights[k] *= alpha; - surfaceContributionSecondMomentWeights[k] *= alpha; + volumeContributionWeights[k] *= alpha; + surfaceContributionWeights[k] *= alpha; volumeSampleNumberWeights[k] *= alpha; surfaceSampleNumberWeights[k] *= alpha; #endif @@ -589,10 +561,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS std::swap(sumOfWeightedStats[tmpIdx0.quot][tmpIdx0.rem], sumOfWeightedStats[tmpIdx1.quot][tmpIdx1.rem]); std::swap(sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem], sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]); #ifdef OPENPGL_VSP_GUIDING - std::swap(volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); - std::swap(surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); - std::swap(volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); - std::swap(surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(volumeContributionWeights[tmpIdx0.quot][tmpIdx0.rem], volumeContributionWeights[tmpIdx1.quot][tmpIdx1.rem]); + std::swap(surfaceContributionWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceContributionWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); std::swap(surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem], surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]); #endif @@ -612,10 +582,8 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS sumOfDistanceWeightes[tmpIdx0.quot][tmpIdx0.rem] += sumOfDistanceWeightes[tmpIdx1.quot][tmpIdx1.rem]; #ifdef OPENPGL_VSP_GUIDING - volumeContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; - surfaceContributionFirstMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionFirstMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; - volumeContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; - surfaceContributionSecondMomentWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionSecondMomentWeights[tmpIdx1.quot][tmpIdx1.rem]; + volumeContributionWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeContributionWeights[tmpIdx1.quot][tmpIdx1.rem]; + surfaceContributionWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceContributionWeights[tmpIdx1.quot][tmpIdx1.rem]; volumeSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += volumeSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; surfaceSampleNumberWeights[tmpIdx0.quot][tmpIdx0.rem] += surfaceSampleNumberWeights[tmpIdx1.quot][tmpIdx1.rem]; #endif @@ -658,14 +626,10 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::SufficientS #ifdef OPENPGL_VSP_GUIDING float weight0 = 0.5f; float weight1 = 0.5f; - volumeContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; - volumeContributionFirstMomentWeights[tmpI.quot][tmpI.rem] *= weight0; - surfaceContributionFirstMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionFirstMomentWeights[tmpI.quot][tmpI.rem]; - surfaceContributionFirstMomentWeights[tmpI.quot][tmpI.rem] *= weight0; - volumeContributionSecondMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionSecondMomentWeights[tmpI.quot][tmpI.rem]; - volumeContributionSecondMomentWeights[tmpI.quot][tmpI.rem] *= weight0; - surfaceContributionSecondMomentWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionSecondMomentWeights[tmpI.quot][tmpI.rem]; - surfaceContributionSecondMomentWeights[tmpI.quot][tmpI.rem] *= weight0; + volumeContributionWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeContributionWeights[tmpI.quot][tmpI.rem]; + volumeContributionWeights[tmpI.quot][tmpI.rem] *= weight0; + surfaceContributionWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceContributionWeights[tmpI.quot][tmpI.rem]; + surfaceContributionWeights[tmpI.quot][tmpI.rem] *= weight0; volumeSampleNumberWeights[tmpJ.quot][tmpJ.rem] = weight1 * volumeSampleNumberWeights[tmpI.quot][tmpI.rem]; volumeSampleNumberWeights[tmpI.quot][tmpI.rem] *= weight0; surfaceSampleNumberWeights[tmpJ.quot][tmpJ.rem] = weight1 * surfaceSampleNumberWeights[tmpI.quot][tmpI.rem]; @@ -1755,7 +1719,7 @@ std::string ParallaxAwareVonMisesFisherWeightedEMFactory::Part #ifdef OPENPGL_VSP_GUIDING template void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, - const size_t numSamples) const + const size_t numSamples, const bool varianceBased) const { // OPENPGL_ASSERT(vmm.isValid()); @@ -1784,19 +1748,31 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum { if (isNextEventVolume(samples[n])) { - sufficientStats.volumeContributionFirstMomentWeights[k] += weight * softAssign.assignments[k]; - OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionFirstMomentWeights[k])); - sufficientStats.volumeContributionSecondMomentWeights[k] += weight * weight * softAssign.assignments[k]; - OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionSecondMomentWeights[k])); + if(!varianceBased) + { + sufficientStats.volumeContributionWeights[k] += weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionWeights[k])); + } + else + { + sufficientStats.volumeContributionWeights[k] += weight * weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionWeights[k])); + } sufficientStats.volumeSampleNumberWeights[k] += softAssign.assignments[k]; OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeSampleNumberWeights[k])); } else { - sufficientStats.surfaceContributionFirstMomentWeights[k] += weight * softAssign.assignments[k]; - OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionFirstMomentWeights[k])); - sufficientStats.surfaceContributionSecondMomentWeights[k] += weight * weight * softAssign.assignments[k]; - OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionSecondMomentWeights[k])); + if(!varianceBased) + { + sufficientStats.surfaceContributionWeights[k] += weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionWeights[k])); + } + else + { + sufficientStats.surfaceContributionWeights[k] += weight * weight * softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionWeights[k])); + } sufficientStats.surfaceSampleNumberWeights[k] += softAssign.assignments[k]; OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceSampleNumberWeights[k])); } @@ -1808,12 +1784,9 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum { for (size_t i = rem; i < VMM::VectorSize; i++) { - vmm._volumeScatterFirstMomentProbabilityWeights[cnt - 1][i] = 0.0f; - vmm._volumeScatterSecondMomentProbabilityWeights[cnt - 1][i] = 0.0f; - sufficientStats.volumeContributionFirstMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.volumeContributionSecondMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.surfaceContributionFirstMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.surfaceContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + vmm._volumeScatterProbabilityWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionWeights[cnt - 1][i] = 0.0f; sufficientStats.volumeSampleNumberWeights[cnt - 1][i] = 0.0f; sufficientStats.surfaceSampleNumberWeights[cnt - 1][i] = 0.0f; } @@ -1826,40 +1799,42 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum embree::vfloat numSurfVolSamples = numVolSamples + numSurfSamples; embree::vfloat estPVol = select(numSurfVolSamples > FLT_EPSILON, numVolSamples / numSurfVolSamples, zeros); - embree::vfloat volumeContributionFirstMomentWeight = - select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionFirstMomentWeights[k] / numVolSamples, zeros); - embree::vfloat surfaceContributionFirstMomentWeight = - select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionFirstMomentWeights[k] / numSurfSamples, zeros); - embree::vfloat sumContributionFirstMomentWeight = - (surfaceContributionFirstMomentWeight * (ones - estPVol)) + (volumeContributionFirstMomentWeight * estPVol); - vmm._volumeScatterFirstMomentProbabilityWeights[k] = - select(sumContributionFirstMomentWeight > FLT_EPSILON, (volumeContributionFirstMomentWeight * estPVol) / sumContributionFirstMomentWeight, zeros); - - embree::vfloat volumeContributionSecondMomentWeight = - select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionSecondMomentWeights[k] / numVolSamples, zeros); - volumeContributionSecondMomentWeight *= (estPVol * estPVol); - volumeContributionSecondMomentWeight = select(volumeContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(volumeContributionSecondMomentWeight), zeros); - - embree::vfloat surfaceContributionSecondMomentWeight = - select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionSecondMomentWeights[k] / numSurfSamples, zeros); - surfaceContributionSecondMomentWeight *= (ones - estPVol) * (ones - estPVol); - surfaceContributionSecondMomentWeight = select(surfaceContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(surfaceContributionSecondMomentWeight), zeros); - - embree::vfloat sumContributionSecondMomentWeight = surfaceContributionSecondMomentWeight + volumeContributionSecondMomentWeight; - vmm._volumeScatterSecondMomentProbabilityWeights[k] = - select(sumContributionSecondMomentWeight > FLT_EPSILON, volumeContributionSecondMomentWeight / sumContributionSecondMomentWeight, zeros); + if(!varianceBased) + { + embree::vfloat volumeContributionWeight = + select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionWeights[k] / numVolSamples, zeros); + embree::vfloat surfaceContributionWeight = + select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionWeights[k] / numSurfSamples, zeros); + embree::vfloat sumContributionWeight = + (surfaceContributionWeight * (ones - estPVol)) + (volumeContributionWeight * estPVol); + vmm._volumeScatterProbabilityWeights[k] = + select(sumContributionWeight > FLT_EPSILON, (volumeContributionWeight * estPVol) / sumContributionWeight, zeros); + } + else + { + embree::vfloat volumeContributionSecondMomentWeight = + select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionWeights[k] / numVolSamples, zeros); + volumeContributionSecondMomentWeight *= (estPVol * estPVol); + volumeContributionSecondMomentWeight = select(volumeContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(volumeContributionSecondMomentWeight), zeros); + + embree::vfloat surfaceContributionSecondMomentWeight = + select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionWeights[k] / numSurfSamples, zeros); + surfaceContributionSecondMomentWeight *= (ones - estPVol) * (ones - estPVol); + surfaceContributionSecondMomentWeight = select(surfaceContributionSecondMomentWeight > FLT_EPSILON, embree::sqrt(surfaceContributionSecondMomentWeight), zeros); + + embree::vfloat sumContributionSecondMomentWeight = surfaceContributionSecondMomentWeight + volumeContributionSecondMomentWeight; + vmm._volumeScatterProbabilityWeights[k] = + select(sumContributionSecondMomentWeight > FLT_EPSILON, volumeContributionSecondMomentWeight / sumContributionSecondMomentWeight, zeros); + } } if (rem > 0) { for (size_t i = rem; i < VMM::VectorSize; i++) { - vmm._volumeScatterFirstMomentProbabilityWeights[cnt - 1][i] = 0.0f; - vmm._volumeScatterSecondMomentProbabilityWeights[cnt - 1][i] = 0.0f; - sufficientStats.volumeContributionFirstMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.volumeContributionSecondMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.surfaceContributionFirstMomentWeights[cnt - 1][i] = 0.0f; - sufficientStats.surfaceContributionSecondMomentWeights[cnt - 1][i] = 0.0f; + vmm._volumeScatterProbabilityWeights[cnt - 1][i] = 0.0f; + sufficientStats.volumeContributionWeights[cnt - 1][i] = 0.0f; + sufficientStats.surfaceContributionWeights[cnt - 1][i] = 0.0f; sufficientStats.volumeSampleNumberWeights[cnt - 1][i] = 0.0f; sufficientStats.surfaceSampleNumberWeights[cnt - 1][i] = 0.0f; } diff --git a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h index e484da5a..6aa38a9d 100644 --- a/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMSurfaceSamplingDistribution.h @@ -157,9 +157,9 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMSurfaceSamplingDistributio } #ifdef OPENPGL_VSP_GUIDING - float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + float volumeScatterProbability(Vector3 dir) const override { - return m_liDistribution.volumeScatterProbability(dir, contributionBased); + return m_liDistribution.volumeScatterProbability(dir); } #endif }; diff --git a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h index 0350c9d9..c66021b1 100644 --- a/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h +++ b/openpgl/directional/vmm/VMMVolumeSamplingDistribution.h @@ -189,9 +189,9 @@ struct __aligned(TVMMDistribution::VectorSize * 4) VMMVolumeSamplingDistribution } #ifdef OPENPGL_VSP_GUIDING - float volumeScatterProbability(Vector3 dir, bool contributionBased) const override + float volumeScatterProbability(Vector3 dir) const override { - return m_liDistribution.volumeScatterProbability(dir, contributionBased); + return m_liDistribution.volumeScatterProbability(dir); } #endif }; diff --git a/openpgl/field/Field.h b/openpgl/field/Field.h index 10e55306..ed4e9c16 100644 --- a/openpgl/field/Field.h +++ b/openpgl/field/Field.h @@ -54,6 +54,9 @@ struct Field bool useStochasticNNLookUp{false}; bool useISNNLookUp{false}; bool deterministic{false}; +#ifdef OPENPGL_VSP_GUIDING + bool varianceBasedVSP{false}; +#endif float decayOnSpatialSplit{0.25f}; std::string toString() const; @@ -80,7 +83,9 @@ struct Field m_useStochasticNNLookUp = settings.settings.useStochasticNNLookUp; m_useISNNLookUp = settings.settings.useISNNLookUp; m_spatialSubdivBuilderSettings = settings.settings.spatialSubdivBuilderSettings; - +#ifdef OPENPGL_VSP_GUIDING + m_vspVarianceBased = settings.settings.varianceBasedVSP; +#endif m_distributionFactorySettings = settings.distributionFactorySettings; samples_.reserve(1e6); } @@ -272,6 +277,9 @@ struct Field os.write(reinterpret_cast(&m_iteration), sizeof(m_iteration)); os.write(reinterpret_cast(&m_totalSPP), sizeof(m_totalSPP)); os.write(reinterpret_cast(&m_deterministic), sizeof(m_deterministic)); +#ifdef OPENPGL_VSP_GUIDING + os.write(reinterpret_cast(&m_vspVarianceBased), sizeof(m_vspVarianceBased)); +#endif os.write(reinterpret_cast(&m_fitRegions), sizeof(m_fitRegions)); os.write(reinterpret_cast(&m_isSceneBoundsSet), sizeof(m_isSceneBoundsSet)); os.write(reinterpret_cast(&m_sceneBounds), sizeof(m_sceneBounds)); @@ -304,6 +312,9 @@ struct Field is.read(reinterpret_cast(&m_iteration), sizeof(m_iteration)); is.read(reinterpret_cast(&m_totalSPP), sizeof(m_totalSPP)); is.read(reinterpret_cast(&m_deterministic), sizeof(m_deterministic)); +#ifdef OPENPGL_VSP_GUIDING + is.read(reinterpret_cast(&m_vspVarianceBased), sizeof(m_vspVarianceBased)); +#endif is.read(reinterpret_cast(&m_fitRegions), sizeof(m_fitRegions)); is.read(reinterpret_cast(&m_isSceneBoundsSet), sizeof(m_isSceneBoundsSet)); is.read(reinterpret_cast(&m_sceneBounds), sizeof(m_sceneBounds)); @@ -465,7 +476,7 @@ struct Field #ifdef OPENPGL_VSP_GUIDING m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, - regionStorage.second.m_end - regionStorage.second.m_begin); + regionStorage.second.m_end - regionStorage.second.m_begin, m_vspVarianceBased); #endif // TODO: we should move setting the pivot to the factory regionStorage.first.distribution._pivotPosition = sampleMean; @@ -566,7 +577,7 @@ struct Field #ifdef OPENPGL_VSP_GUIDING m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, - regionStorage.second.m_end - regionStorage.second.m_begin); + regionStorage.second.m_end - regionStorage.second.m_begin, m_vspVarianceBased); #endif regionStorage.first.valid = regionStorage.first.isValid(); #ifdef OPENPGL_DEBUG_MODE @@ -744,6 +755,10 @@ struct Field // if the fitting process should be deterministic (i.e, samples are sorted before training) bool m_deterministic{false}; +#ifdef OPENPGL_VSP_GUIDING + bool m_vspVarianceBased{false}; +#endif + bool m_isSceneBoundsSet{false}; BBox m_sceneBounds; diff --git a/openpgl/include/openpgl/config.h b/openpgl/include/openpgl/config.h index 8cf2509a..f48bfe70 100644 --- a/openpgl/include/openpgl/config.h +++ b/openpgl/include/openpgl/config.h @@ -124,6 +124,9 @@ extern "C" void *directionalDistributionArguments; // for debugging bool deterministic{false}; +#ifdef OPENPGL_VSP_GUIDING + bool varianceBasedVSP{false}; +#endif PGLDebugArguments debugArguments; }; diff --git a/openpgl/include/openpgl/cpp/FieldConfig.h b/openpgl/include/openpgl/cpp/FieldConfig.h index 88608f3d..956d5efe 100644 --- a/openpgl/include/openpgl/cpp/FieldConfig.h +++ b/openpgl/include/openpgl/cpp/FieldConfig.h @@ -60,6 +60,8 @@ struct FieldConfig */ void SetUseKnnIsLookup(const bool useKnnIsLookup); + void SetVarianceBasedVSP(const bool varianceBasedVSP); + /** * @brief For debugging and benchmarking the update of the spatial structure this function can disable * the training of the directional distribution during the update iterations. @@ -104,5 +106,12 @@ OPENPGL_INLINE void FieldConfig::SetUseKnnIsLookup(const bool useKnnIsLookup) reinterpret_cast(m_args.spatialSturctureArguments)->isKnnLookup = useKnnIsLookup; } +#ifdef OPENPGL_VSP_GUIDING +OPENPGL_INLINE void FieldConfig::SetVarianceBasedVSP(const bool varianceBasedVSP) +{ + m_args.varianceBasedVSP = varianceBasedVSP; +} +#endif + } // namespace cpp } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h index 5157a493..89899b5a 100644 --- a/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/SurfaceSamplingDistribution.h @@ -148,7 +148,7 @@ struct SurfaceSamplingDistribution #endif #ifdef OPENPGL_VSP_GUIDING - float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; + float VolumeScatterProbability(pgl_vec3f &direction) const; #endif /////////////////////////////////////// /// Future plans @@ -291,10 +291,10 @@ OPENPGL_INLINE pgl_vec3f SurfaceSamplingDistribution::Irradiance(pgl_vec3f &norm #endif #ifdef OPENPGL_VSP_GUIDING -OPENPGL_INLINE float SurfaceSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const +OPENPGL_INLINE float SurfaceSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction) const { OPENPGL_ASSERT(m_surfaceSamplingDistributionHandle); - return pglSurfaceSamplingDistributionVolumeScatterProbability(m_surfaceSamplingDistributionHandle, direction, contributionBased); + return pglSurfaceSamplingDistributionVolumeScatterProbability(m_surfaceSamplingDistributionHandle, direction); } #endif } // namespace cpp diff --git a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h index b369f563..1a19d5fa 100644 --- a/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h +++ b/openpgl/include/openpgl/cpp/VolumeSamplingDistribution.h @@ -165,7 +165,7 @@ struct VolumeSamplingDistribution #endif #ifdef OPENPGL_VSP_GUIDING - float VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const; + float VolumeScatterProbability(pgl_vec3f &direction) const; #endif /////////////////////////////////////// /// Future plans @@ -312,10 +312,10 @@ OPENPGL_INLINE pgl_vec3f VolumeSamplingDistribution::Fluence(const bool directLi #endif #ifdef OPENPGL_VSP_GUIDING -OPENPGL_INLINE float VolumeSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction, bool contributionBased) const +OPENPGL_INLINE float VolumeSamplingDistribution::VolumeScatterProbability(pgl_vec3f &direction) const { OPENPGL_ASSERT(m_volumeSamplingDistributionHandle); - return pglVolumeSamplingDistributionVolumeScatterProbability(m_volumeSamplingDistributionHandle, direction, contributionBased); + return pglVolumeSamplingDistributionVolumeScatterProbability(m_volumeSamplingDistributionHandle, direction); } #endif diff --git a/openpgl/include/openpgl/surfacesamplingdistribution.h b/openpgl/include/openpgl/surfacesamplingdistribution.h index b3aee911..abb6daf7 100644 --- a/openpgl/include/openpgl/surfacesamplingdistribution.h +++ b/openpgl/include/openpgl/surfacesamplingdistribution.h @@ -52,8 +52,7 @@ typedef ManagedObject SurfaceSamplingDistribution; #endif #ifdef OPENPGL_VSP_GUIDING - OPENPGL_CORE_INTERFACE float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction, - bool contributionBased); + OPENPGL_CORE_INTERFACE float pglSurfaceSamplingDistributionVolumeScatterProbability(PGLSurfaceSamplingDistribution surfaceSamplingDistribution, pgl_vec3f direction); #endif #ifdef __cplusplus diff --git a/openpgl/include/openpgl/volumesamplingdistribution.h b/openpgl/include/openpgl/volumesamplingdistribution.h index 5665c890..70d4ba05 100644 --- a/openpgl/include/openpgl/volumesamplingdistribution.h +++ b/openpgl/include/openpgl/volumesamplingdistribution.h @@ -55,8 +55,7 @@ typedef ManagedObject VolumeSamplingDistribution; #endif #ifdef OPENPGL_VSP_GUIDING - OPENPGL_CORE_INTERFACE float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution VolumeSamplingDistribution, pgl_vec3f direction, - bool contributionBased); + OPENPGL_CORE_INTERFACE float pglVolumeSamplingDistributionVolumeScatterProbability(PGLVolumeSamplingDistribution VolumeSamplingDistribution, pgl_vec3f direction); #endif #ifdef __cplusplus } // extern "C" From 3a2ac92887f7f4216df1ee847e0f6495d3b11401 Mon Sep 17 00:00:00 2001 From: "Herholz, Sebastian" Date: Fri, 16 Aug 2024 16:16:54 +0200 Subject: [PATCH 04/15] [vsp] Considering the ZeroValueSamples when estimating the VSP --- openpgl/data/PathSegmentDataStorage.h | 2 +- openpgl/data/SampleData.h | 10 ++++ openpgl/data/SampleDataStorage.h | 2 +- openpgl/directional/dqt/DQTFactory.h | 4 +- .../vmm/AdaptiveSplitandMergeFactory.h | 9 ++-- .../vmm/ParallaxAwareVonMisesFisherMixture.h | 1 - ...llaxAwareVonMisesFisherWeightedEMFactory.h | 49 +++++++++++++------ openpgl/field/Field.h | 14 +++--- openpgl/include/openpgl/data.h | 2 +- 9 files changed, 65 insertions(+), 28 deletions(-) diff --git a/openpgl/data/PathSegmentDataStorage.h b/openpgl/data/PathSegmentDataStorage.h index 87d774e0..8f1bfb49 100644 --- a/openpgl/data/PathSegmentDataStorage.h +++ b/openpgl/data/PathSegmentDataStorage.h @@ -405,7 +405,7 @@ struct PathSegmentDataStorage pglDirection = {dirOut[0], dirOut[1], dirOut[2]}; isd.directionOut = pglDirection; #endif - isd.volume = insideVolume; + isd.flags = flags; #if defined(OPENPGL_PATHSEGMENT_STORAGE_USE_ARRAY) if (m_zero_value_sample_idx + 1 <= m_max_zero_value_sample_size) { diff --git a/openpgl/data/SampleData.h b/openpgl/data/SampleData.h index fc991a05..66087db7 100644 --- a/openpgl/data/SampleData.h +++ b/openpgl/data/SampleData.h @@ -192,6 +192,16 @@ inline bool ZeroValueSampleDataLess(const PGLZeroValueSampleData &compA, const P ))))); } +inline bool isInsideVolume(const PGLZeroValueSampleData &zvsd) +{ + return (zvsd.flags & EInsideVolume); +} + +inline bool isNextEventVolume(const PGLZeroValueSampleData &zvsd) +{ + return (zvsd.flags & ENextEventVolume); +} + inline SampleData *LoadSampleData(const std::string fileName, size_t &numData) { std::ifstream file; diff --git a/openpgl/data/SampleDataStorage.h b/openpgl/data/SampleDataStorage.h index d0688f40..4285cf4a 100644 --- a/openpgl/data/SampleDataStorage.h +++ b/openpgl/data/SampleDataStorage.h @@ -104,7 +104,7 @@ struct SampleDataStorage inline void addZeroValueSample(const ZeroValueSampleData &sample) { - if (sample.volume) + if (isInsideVolume(sample)) { m_volumeContainer.zeroValueSamples.push_back(sample); } diff --git a/openpgl/directional/dqt/DQTFactory.h b/openpgl/directional/dqt/DQTFactory.h index fce46734..57bbd917 100644 --- a/openpgl/directional/dqt/DQTFactory.h +++ b/openpgl/directional/dqt/DQTFactory.h @@ -180,7 +180,9 @@ class DirectionalQuadtreeFactory const SampleStatistics &sampleStatistics) const {} - void updateVolumeScatterProbability(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const {} + void updateVolumeScatterProbability(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const ZeroValueSampleData *zeroValueSamples, + const size_t numZeroValueSamples, const bool varianceBased) const + {} void fit(Distribution &dist, Statistics &stats, const SampleData *samples, const size_t numSamples, const Configuration &cfg, FittingStatistics &fitStats) { diff --git a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h index ef610848..98e9ef6b 100644 --- a/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h +++ b/openpgl/directional/vmm/AdaptiveSplitandMergeFactory.h @@ -126,7 +126,8 @@ struct AdaptiveSplitAndMergeFactory void updateFluenceEstimate(VMM &vmm, const SampleData *samples, const size_t numSamples, const size_t numZeroValueSamples, const SampleStatistics &sampleStatistics) const; - void updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const; + void updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, const ZeroValueSampleData *zeroValueSamples, + const size_t numZeroValueSamples, const bool varianceBased) const; std::string toString() const { @@ -470,10 +471,12 @@ void AdaptiveSplitAndMergeFactory::updateFluenceEstimate(VMM & } template -void AdaptiveSplitAndMergeFactory::updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, const bool varianceBased) const +void AdaptiveSplitAndMergeFactory::updateVolumeScatterProbability(VMM &vmm, Statistics &stats, const SampleData *samples, const size_t numSamples, + const ZeroValueSampleData *zeroValueSamples, const size_t numZeroValueSamples, + const bool varianceBased) const { WeightedEMFactory factory = WeightedEMFactory(); - factory.updateVolumeScatterProbability(vmm, stats.sufficientStatistics, samples, numSamples, varianceBased); + factory.updateVolumeScatterProbability(vmm, stats.sufficientStatistics, samples, numSamples, zeroValueSamples, numZeroValueSamples, varianceBased); } } // namespace openpgl diff --git a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h index 144aa631..3c781ea8 100644 --- a/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h +++ b/openpgl/directional/vmm/ParallaxAwareVonMisesFisherMixture.h @@ -422,7 +422,6 @@ void ParallaxAwareVonMisesFisherMixture::Part #ifdef OPENPGL_VSP_GUIDING template void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolumeScatterProbability(VMM &vmm, SufficientStatistics &sufficientStats, const SampleData *samples, - const size_t numSamples, const bool varianceBased) const + const size_t numSamples, const ZeroValueSampleData *zeroValueSamples, + const size_t numZeroValueSamples, const bool varianceBased) const { // OPENPGL_ASSERT(vmm.isValid()); - if (numSamples == 0) + if (numSamples + numZeroValueSamples == 0) { return; } @@ -1748,7 +1750,7 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum { if (isNextEventVolume(samples[n])) { - if(!varianceBased) + if (!varianceBased) { sufficientStats.volumeContributionWeights[k] += weight * softAssign.assignments[k]; OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeContributionWeights[k])); @@ -1763,7 +1765,7 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum } else { - if(!varianceBased) + if (!varianceBased) { sufficientStats.surfaceContributionWeights[k] += weight * softAssign.assignments[k]; OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceContributionWeights[k])); @@ -1780,6 +1782,29 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum } } + for (size_t n = 0; n < numZeroValueSamples; n++) + { + pgl_vec3f direction = zeroValueSamples[n].direction; + const Vector3 sampleDirection(direction.x, direction.y, direction.z); + + if (vmm.softAssignment(sampleDirection, softAssign)) + { + for (size_t k = 0; k < cnt; k++) + { + if (isNextEventVolume(zeroValueSamples[n])) + { + sufficientStats.volumeSampleNumberWeights[k] += softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.volumeSampleNumberWeights[k])); + } + else + { + sufficientStats.surfaceSampleNumberWeights[k] += softAssign.assignments[k]; + OPENPGL_ASSERT(embree::isvalid(sufficientStats.surfaceSampleNumberWeights[k])); + } + } + } + } + if (rem > 0) { for (size_t i = rem; i < VMM::VectorSize; i++) @@ -1799,16 +1824,12 @@ void ParallaxAwareVonMisesFisherWeightedEMFactory::updateVolum embree::vfloat numSurfVolSamples = numVolSamples + numSurfSamples; embree::vfloat estPVol = select(numSurfVolSamples > FLT_EPSILON, numVolSamples / numSurfVolSamples, zeros); - if(!varianceBased) + if (!varianceBased) { - embree::vfloat volumeContributionWeight = - select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionWeights[k] / numVolSamples, zeros); - embree::vfloat surfaceContributionWeight = - select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionWeights[k] / numSurfSamples, zeros); - embree::vfloat sumContributionWeight = - (surfaceContributionWeight * (ones - estPVol)) + (volumeContributionWeight * estPVol); - vmm._volumeScatterProbabilityWeights[k] = - select(sumContributionWeight > FLT_EPSILON, (volumeContributionWeight * estPVol) / sumContributionWeight, zeros); + embree::vfloat volumeContributionWeight = select(numVolSamples > FLT_EPSILON, sufficientStats.volumeContributionWeights[k] / numVolSamples, zeros); + embree::vfloat surfaceContributionWeight = select(numSurfSamples > FLT_EPSILON, sufficientStats.surfaceContributionWeights[k] / numSurfSamples, zeros); + embree::vfloat sumContributionWeight = (surfaceContributionWeight * (ones - estPVol)) + (volumeContributionWeight * estPVol); + vmm._volumeScatterProbabilityWeights[k] = select(sumContributionWeight > FLT_EPSILON, (volumeContributionWeight * estPVol) / sumContributionWeight, zeros); } else { diff --git a/openpgl/field/Field.h b/openpgl/field/Field.h index ed4e9c16..117241f8 100644 --- a/openpgl/field/Field.h +++ b/openpgl/field/Field.h @@ -474,9 +474,10 @@ struct Field regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif #ifdef OPENPGL_VSP_GUIDING - m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, - samples.data() + regionStorage.second.m_begin, - regionStorage.second.m_end - regionStorage.second.m_begin, m_vspVarianceBased); + m_distributionFactory.updateVolumeScatterProbability( + regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, + regionStorage.second.m_end - regionStorage.second.m_begin, zeroValueSamples.data() + regionStorage.second.m_is_begin, + regionStorage.second.m_is_end - regionStorage.second.m_is_begin, m_vspVarianceBased); #endif // TODO: we should move setting the pivot to the factory regionStorage.first.distribution._pivotPosition = sampleMean; @@ -575,9 +576,10 @@ struct Field regionStorage.second.m_is_end - regionStorage.second.m_is_begin); #endif #ifdef OPENPGL_VSP_GUIDING - m_distributionFactory.updateVolumeScatterProbability(regionStorage.first.distribution, regionStorage.first.trainingStatistics, - samples.data() + regionStorage.second.m_begin, - regionStorage.second.m_end - regionStorage.second.m_begin, m_vspVarianceBased); + m_distributionFactory.updateVolumeScatterProbability( + regionStorage.first.distribution, regionStorage.first.trainingStatistics, samples.data() + regionStorage.second.m_begin, + regionStorage.second.m_end - regionStorage.second.m_begin, zeroValueSamples.data() + regionStorage.second.m_is_begin, + regionStorage.second.m_is_end - regionStorage.second.m_is_begin, m_vspVarianceBased); #endif regionStorage.first.valid = regionStorage.first.isValid(); #ifdef OPENPGL_DEBUG_MODE diff --git a/openpgl/include/openpgl/data.h b/openpgl/include/openpgl/data.h index f0cfb4ec..cb6cb02e 100644 --- a/openpgl/include/openpgl/data.h +++ b/openpgl/include/openpgl/data.h @@ -77,7 +77,7 @@ struct PGLZeroValueSampleData pgl_direction directionOut; #endif /// if the position is inside a volume - bool volume; + uint32_t flags; }; /** From 25d7c107e3379ee555da600f1c69fa9eaaaea716 Mon Sep 17 00:00:00 2001 From: Herholz Sebastian Date: Mon, 19 Aug 2024 10:36:00 -0500 Subject: [PATCH 05/15] [vsp] Adding support to enable VSP guiding while disabling radiance caching --- openpgl/data/Range.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpgl/data/Range.h b/openpgl/data/Range.h index aadf9d70..d976636e 100644 --- a/openpgl/data/Range.h +++ b/openpgl/data/Range.h @@ -12,7 +12,7 @@ struct Range size_t m_begin{0}; size_t m_end{0}; -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) size_t m_is_begin{0}; size_t m_is_end{0}; #endif @@ -25,7 +25,7 @@ struct Range OPENPGL_ASSERT(int(m_end) - int(m_begin) >= 0); return m_end - m_begin; } -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) inline size_t sizeZeroValueSamples() const { OPENPGL_ASSERT(int(m_is_end) - int(m_is_begin) >= 0); @@ -36,7 +36,7 @@ struct Range { m_begin = 0; m_end = 0; -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) m_is_begin = 0; m_is_end = 0; #endif @@ -46,7 +46,7 @@ struct Range { os.write(reinterpret_cast(&m_begin), sizeof(m_begin)); os.write(reinterpret_cast(&m_end), sizeof(m_end)); -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) os.write(reinterpret_cast(&m_is_begin), sizeof(m_is_begin)); os.write(reinterpret_cast(&m_is_end), sizeof(m_is_end)); #endif @@ -56,7 +56,7 @@ struct Range { is.read(reinterpret_cast(&m_begin), sizeof(m_begin)); is.read(reinterpret_cast(&m_end), sizeof(m_end)); -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) is.read(reinterpret_cast(&m_is_begin), sizeof(m_is_begin)); is.read(reinterpret_cast(&m_is_end), sizeof(m_is_end)); #endif @@ -66,7 +66,7 @@ struct Range { bool equal = true; if (m_begin != b.m_begin || m_end != b.m_end -#ifdef OPENPGL_RADIANCE_CACHES +#if defined(OPENPGL_RADIANCE_CACHES) || defined(OPENPGL_VSP_GUIDING) || m_is_begin != b.m_is_begin || m_is_end != b.m_is_end #endif ) From 094ddd2fd82d43750cc4e897b281255e1973c1f0 Mon Sep 17 00:00:00 2001 From: "Herholz, Sebastian" Date: Tue, 3 Dec 2024 13:00:10 +0100 Subject: [PATCH 06/15] [vsp] Adding VSP support to the ImageSpaceGuidingBuffer --- openpgl/api/api.cpp | 14 +- openpgl/imagespace/ImageSpaceGuidingBuffer.h | 519 +++++++++++++++--- openpgl/include/openpgl/common.h | 10 + .../openpgl/cpp/ImageSpaceGuidingBuffer.h | 75 ++- openpgl/include/openpgl/data.h | 26 +- .../include/openpgl/imagespaceguidingbuffer.h | 8 +- 6 files changed, 563 insertions(+), 89 deletions(-) diff --git a/openpgl/api/api.cpp b/openpgl/api/api.cpp index 805d68d9..1ed85112 100644 --- a/openpgl/api/api.cpp +++ b/openpgl/api/api.cpp @@ -890,9 +890,9 @@ extern "C" OPENPGL_DLLEXPORT void pglReleaseString(PGLString str) // ImageSpaceGuidingBuffer /////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -extern "C" OPENPGL_DLLEXPORT PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBuffer(const pgl_point2i resolution) +extern "C" OPENPGL_DLLEXPORT PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBuffer(const PGLImageSpaceGuidingBufferConfig cfg) { - return (PGLImageSpaceGuidingBuffer) new openpgl::ImageSpaceGuidingBuffer(resolution, false); + return (PGLImageSpaceGuidingBuffer) new openpgl::ImageSpaceGuidingBuffer(cfg); } extern "C" OPENPGL_DLLEXPORT PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBufferFromFile(const char *fileName) @@ -924,12 +924,20 @@ extern "C" OPENPGL_DLLEXPORT void pglImageSpaceGuidingBufferStore(PGLImageSpaceG gImageSpaceGuidingBuffer->store(fileName); } -extern "C" OPENPGL_DLLEXPORT pgl_vec3f pglImageSpaceGuidingBufferGetPixelContributionEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel) +extern "C" OPENPGL_DLLEXPORT pgl_vec3f pglImageSpaceGuidingBufferGetContributionEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel) { auto *gImageSpaceGuidingBuffer = (openpgl::ImageSpaceGuidingBuffer *)imageSpaceGuidingBuffer; return gImageSpaceGuidingBuffer->getContributionEstimate(pixel); } +#if defined(OPENPGL_VSP_GUIDING) +extern "C" OPENPGL_DLLEXPORT float pglImageSpaceGuidingBufferGetVolumeScatterProbabilityEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel) +{ + auto *gImageSpaceGuidingBuffer = (openpgl::ImageSpaceGuidingBuffer *)imageSpaceGuidingBuffer; + return gImageSpaceGuidingBuffer->getVolumeScatterProbabilityEstimate(pixel); +} +#endif + extern "C" OPENPGL_DLLEXPORT bool pglImageSpaceGuidingBufferIsReady(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer) { auto *gImageSpaceGuidingBuffer = (openpgl::ImageSpaceGuidingBuffer *)imageSpaceGuidingBuffer; diff --git a/openpgl/imagespace/ImageSpaceGuidingBuffer.h b/openpgl/imagespace/ImageSpaceGuidingBuffer.h index 468ac915..2f2822fe 100644 --- a/openpgl/imagespace/ImageSpaceGuidingBuffer.h +++ b/openpgl/imagespace/ImageSpaceGuidingBuffer.h @@ -25,6 +25,9 @@ #define TINYEXR_IMPLEMENTATION #include +//#define VSP_DENOISE_AFTER_PRODUCT +#define VSP_USE_PVOL_EST + namespace openpgl { @@ -35,14 +38,12 @@ struct ImageSpaceGuidingBuffer Buffers(pgl_point2i resolution) : numPixels(resolution.x * resolution.y) { contribution = new pgl_vec3f[numPixels]; - secondMoment = new pgl_vec3f[numPixels]; albedo = new pgl_vec3f[numPixels]; normal = new pgl_vec3f[numPixels]; spp = new float[numPixels]; filteredContribution = new pgl_vec3f[numPixels]; - filteredSecondMoment = new pgl_vec3f[numPixels]; } Buffers(const Buffers &buffer) = delete; @@ -52,14 +53,12 @@ struct ImageSpaceGuidingBuffer ~Buffers() { delete[] contribution; - delete[] secondMoment; delete[] albedo; delete[] normal; delete[] spp; delete[] filteredContribution; - delete[] filteredSecondMoment; } void reset() @@ -73,14 +72,12 @@ struct ImageSpaceGuidingBuffer #endif { contribution[pIdx] = {0.f, 0.f, 0.f}; - secondMoment[pIdx] = {0.f, 0.f, 0.f}; albedo[pIdx] = {0.f, 0.f, 0.f}; normal[pIdx] = {0.f, 0.f, 0.f}; spp[pIdx] = 0.f; filteredContribution[pIdx] = {0.f, 0.f, 0.f}; - filteredSecondMoment[pIdx] = {0.f, 0.f, 0.f}; } }); } @@ -88,20 +85,31 @@ struct ImageSpaceGuidingBuffer int numPixels{0}; pgl_vec3f *contribution{nullptr}; - pgl_vec3f *secondMoment{nullptr}; pgl_vec3f *albedo{nullptr}; pgl_vec3f *normal{nullptr}; float *spp{nullptr}; pgl_vec3f *filteredContribution{nullptr}; - pgl_vec3f *filteredSecondMoment{nullptr}; }; - ImageSpaceGuidingBuffer(pgl_point2i resolution, bool useSecondMoment) : m_useSecondMoment(useSecondMoment), m_resolution(resolution) + ImageSpaceGuidingBuffer(PGLImageSpaceGuidingBufferConfig cfg) : m_cfg(cfg) { - m_denoiser = new Denoiser(m_resolution, false); - m_contributionEstimateBuffers = new Buffers(m_resolution); + m_resolution = cfg.resolution; + m_denoiser = new Denoiser(cfg.resolution, false); + if(m_cfg.contributionEstimate) { + m_contributionEstimateBuffers = new Buffers(cfg.resolution); + } +#if defined(OPENPGL_VSP_GUIDING) + if(m_cfg.vspEstimate) { + m_surfaceContributionEstimateBuffers = new Buffers(cfg.resolution); + m_volumeContributionEstimateBuffers = new Buffers(cfg.resolution); + m_pVolBuffer = new float[m_resolution.x * m_resolution.y]; + m_filteredPVolBuffer = new float[m_resolution.x * m_resolution.y]; + m_vspContributionBuffer = new float[m_resolution.x * m_resolution.y]; + } +#endif + this->reset(); m_ready = false; } @@ -132,11 +140,54 @@ struct ImageSpaceGuidingBuffer const size_t numPixels = m_resolution.x * m_resolution.y; m_denoiser = new Denoiser(m_resolution, false); - m_contributionEstimateBuffers = new Buffers(m_resolution); std::vector layer_names; tinyexr::GetLayers(exrHeader, layer_names); + // identify config based on the stored layers + m_cfg.contributionEstimate = false; + m_cfg.contributionType = PGLContributionTypes::EFirstMoment; +#if defined(OPENPGL_VSP_GUIDING) + m_cfg.contributionEstimate = false; + m_cfg.contributionType = PGLContributionTypes::EFirstMoment; +#endif + for (int i = 0; i < layer_names.size(); i++) { + std::string layerName = layer_names[i]; + if (layerName == "Contrib" || layerName == "Contrib2nd") + { + m_cfg.contributionEstimate = true; + if(layerName == "Contrib2nd") { + m_cfg.contributionType = PGLContributionTypes::ESecondMoment; + } + } +#if defined(OPENPGL_VSP_GUIDING) + if (layerName == "surfContrib" || layerName == "surfContrib2nd") + { + m_cfg.vspEstimate = true; + if(layerName == "surfContrib2nd") { + m_cfg.vspType = PGLVSPTypes::EContribution; + } + } +#endif + } + + std::cout << "m_cfg.contributionEstimate = " << m_cfg.contributionEstimate << std::endl; + if (m_cfg.contributionEstimate) { + m_contributionEstimateBuffers = new Buffers(m_resolution); + } + + m_cfg.resolution = m_resolution; +#if defined(OPENPGL_VSP_GUIDING) + std::cout << "m_cfg.vspEstimate = " << m_cfg.vspEstimate << std::endl; + if(m_cfg.vspEstimate) { + m_surfaceContributionEstimateBuffers = new Buffers(m_resolution); + m_volumeContributionEstimateBuffers = new Buffers(m_resolution); + m_pVolBuffer = new float[m_resolution.x * m_resolution.y]; + m_filteredPVolBuffer = new float[m_resolution.x * m_resolution.y]; + m_vspContributionBuffer = new float[m_resolution.x * m_resolution.y]; + } +#endif + for (int i = 0; i < layer_names.size(); i++) { std::string layerName = layer_names[i]; @@ -175,26 +226,18 @@ struct ImageSpaceGuidingBuffer } float *bufferPtr = nullptr; - if (layerName == "Contrib") + if (layerName == "Contrib" || layerName == "Contrib2nd") { bufferPtr = (float *)m_contributionEstimateBuffers->filteredContribution; } - else if (layerName == "Contribt2nd") - { - bufferPtr = (float *)m_contributionEstimateBuffers->filteredSecondMoment; - } else if (layerName == "Spp") { bufferPtr = (float *)m_contributionEstimateBuffers->spp; } - else if (layerName == "ContribRaw") + else if (layerName == "ContribRaw" || layerName == "Contrib2ndRaw") { bufferPtr = (float *)m_contributionEstimateBuffers->contribution; } - else if (layerName == "Contribt2ndRaw") - { - bufferPtr = (float *)m_contributionEstimateBuffers->secondMoment; - } else if (layerName == "Albedo") { bufferPtr = (float *)m_contributionEstimateBuffers->albedo; @@ -203,6 +246,60 @@ struct ImageSpaceGuidingBuffer { bufferPtr = (float *)m_contributionEstimateBuffers->normal; } +#if defined(OPENPGL_VSP_GUIDING) + if (layerName == "surfContrib" || layerName == "surfContrib2nd") + { + bufferPtr = (float *)m_surfaceContributionEstimateBuffers->filteredContribution; + } + else if (layerName == "surfSpp") + { + bufferPtr = (float *)m_surfaceContributionEstimateBuffers->spp; + } + else if (layerName == "surfContribRaw" || layerName == "surfContrib2ndRaw") + { + bufferPtr = (float *)m_surfaceContributionEstimateBuffers->contribution; + } + else if (layerName == "surfAlbedo") + { + bufferPtr = (float *)m_surfaceContributionEstimateBuffers->albedo; + } + else if (layerName == "surfN") + { + bufferPtr = (float *)m_surfaceContributionEstimateBuffers->normal; + } + else if (layerName == "volContrib" || layerName == "volContrib2nd") + { + bufferPtr = (float *)m_volumeContributionEstimateBuffers->filteredContribution; + } + else if (layerName == "volSpp") + { + bufferPtr = (float *)m_volumeContributionEstimateBuffers->spp; + } + else if (layerName == "volContribRaw" || layerName == "volContrib2ndRaw") + { + bufferPtr = (float *)m_volumeContributionEstimateBuffers->contribution; + } + else if (layerName == "volAlbedo") + { + bufferPtr = (float *)m_volumeContributionEstimateBuffers->albedo; + } + else if (layerName == "volN") + { + bufferPtr = (float *)m_volumeContributionEstimateBuffers->normal; + } + else if (layerName == "VSP") + { + bufferPtr = (float *)m_vspContributionBuffer; + } + else if (layerName == "PVolRAW") + { + bufferPtr = (float *)m_pVolBuffer; + } + else if (layerName == "PVol") + { + bufferPtr = (float *)m_filteredPVolBuffer; + } +#endif else { } @@ -251,6 +348,13 @@ struct ImageSpaceGuidingBuffer { delete m_denoiser; delete m_contributionEstimateBuffers; +#if defined(OPENPGL_VSP_GUIDING) + delete m_surfaceContributionEstimateBuffers; + delete m_volumeContributionEstimateBuffers; + delete m_pVolBuffer; + delete m_filteredPVolBuffer; + delete m_vspContributionBuffer; +#endif } void store(const std::string &fileName) const @@ -267,40 +371,125 @@ struct ImageSpaceGuidingBuffer std::vector numChannels; std::vector layerChannels; std::vector channelValues; - int cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "Contrib"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->filteredContribution); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "Contribt2nd"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->filteredSecondMoment); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "Spp"); - numChannels.emplace_back(1); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->spp); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "ContribRaw"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->contribution); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "Contribt2ndRaw"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->secondMoment); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "Albedo"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->albedo); - - cIdx = layerChannels.size(); - layerChannels.emplace_back(cIdx, "N"); - numChannels.emplace_back(3); - channelValues.emplace_back((const float *)m_contributionEstimateBuffers->normal); + int cIdx = 0; + if(m_cfg.contributionEstimate) { + cIdx = layerChannels.size(); + if (m_cfg.contributionType == PGLContributionTypes::EFirstMoment) { + layerChannels.emplace_back(cIdx, "Contrib"); + } else { + layerChannels.emplace_back(cIdx, "Contrib2nd"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_contributionEstimateBuffers->filteredContribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "Spp"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_contributionEstimateBuffers->spp); + + cIdx = layerChannels.size(); + if (m_cfg.contributionType == PGLContributionTypes::EFirstMoment) { + layerChannels.emplace_back(cIdx, "ContribRaw"); + } else { + layerChannels.emplace_back(cIdx, "Contrib2ndRaw"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_contributionEstimateBuffers->contribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "Albedo"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_contributionEstimateBuffers->albedo); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "N"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_contributionEstimateBuffers->normal); + } +#if defined(OPENPGL_VSP_GUIDING) + if(m_cfg.vspEstimate) { + cIdx = layerChannels.size(); + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + layerChannels.emplace_back(cIdx, "surfContrib"); + } else { + layerChannels.emplace_back(cIdx, "surfContrib2nd"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->filteredContribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "surfSpp"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->spp); + + cIdx = layerChannels.size(); + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + layerChannels.emplace_back(cIdx, "surfContribRaw"); + } else { + layerChannels.emplace_back(cIdx, "surfContrib2ndRaw"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->contribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "surfAlbedo"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->albedo); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "surfN"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->normal); + + cIdx = layerChannels.size(); + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + layerChannels.emplace_back(cIdx, "volContrib"); + } else { + layerChannels.emplace_back(cIdx, "volContrib2nd"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->filteredContribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "volSpp"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->spp); + + cIdx = layerChannels.size(); + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + layerChannels.emplace_back(cIdx, "volContribRaw"); + } else { + layerChannels.emplace_back(cIdx, "volContrib2ndRaw"); + } + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->contribution); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "volAlbedo"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->albedo); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "volN"); + numChannels.emplace_back(3); + channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->normal); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "VSP"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_vspContributionBuffer); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "PVolRAW"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_pVolBuffer); + + cIdx = layerChannels.size(); + layerChannels.emplace_back(cIdx, "PVol"); + numChannels.emplace_back(1); + channelValues.emplace_back((const float *)m_filteredPVolBuffer); + } +#endif int totalNumLayers = layerChannels.size(); int totalNumChannels = 0; @@ -442,39 +631,183 @@ struct ImageSpaceGuidingBuffer void update() { - if (m_useSecondMoment) - { - m_denoiser->denoise(m_contributionEstimateBuffers->contribution, m_contributionEstimateBuffers->secondMoment, m_contributionEstimateBuffers->normal, - m_contributionEstimateBuffers->albedo, m_contributionEstimateBuffers->filteredContribution, m_contributionEstimateBuffers->filteredSecondMoment); - } - else - { + if(m_cfg.contributionEstimate) { m_denoiser->denoise(m_contributionEstimateBuffers->contribution, m_contributionEstimateBuffers->normal, m_contributionEstimateBuffers->albedo, m_contributionEstimateBuffers->filteredContribution); } +#if defined(OPENPGL_VSP_GUIDING) + if(m_cfg.vspEstimate) { + const int numPixels = m_resolution.x * m_resolution.y; + +#ifdef USE_EMBREE_PARALLEL + embree::parallel_for(0, (int)numPixels, 1, [&](const embree::range &r) { + for (size_t pIdx = r.begin(); pIdx < r.end(); pIdx++) +#else + tbb::parallel_for(tbb::blocked_range(0, numPixels), [&](tbb::blocked_range r) { + for (int pIdx = r.begin(); pIdx < r.end(); ++pIdx) +#endif + { + const float surfaceSampleCount = m_surfaceContributionEstimateBuffers->spp[pIdx]; + const float volumeSampleCount = m_volumeContributionEstimateBuffers->spp[pIdx]; + const float pVolEst = volumeSampleCount / (surfaceSampleCount + volumeSampleCount); + m_pVolBuffer[pIdx] = pVolEst; +#ifdef VSP_DENOISE_AFTER_PRODUCT + m_surfaceContributionEstimateBuffers->scaledContribution[pIdx] = m_surfaceContributionEstimateBuffers->contribution[pIdx] * (1 - pVolEst); + m_volumeContributionEstimateBuffers->scaledContribution[pIdx] = m_volumeContributionEstimateBuffers->contribution[pIdx] * pVolEst; +#endif + } + }); + + m_denoiser->denoise(m_pVolBuffer, m_filteredPVolBuffer); + +#ifndef VSP_DENOISE_AFTER_PRODUCT + m_denoiser->denoise(m_surfaceContributionEstimateBuffers->contribution, m_surfaceContributionEstimateBuffers->normal, m_surfaceContributionEstimateBuffers->albedo, m_surfaceContributionEstimateBuffers->filteredContribution); + m_denoiser->denoise(m_volumeContributionEstimateBuffers->contribution, m_volumeContributionEstimateBuffers->normal, m_volumeContributionEstimateBuffers->albedo, m_volumeContributionEstimateBuffers->filteredContribution); +#else + m_denoiser->denoise(m_surfaceContributionEstimateBuffers->scaledContribution, m_surfaceContributionEstimateBuffers->normal, m_surfaceContributionEstimateBuffers->albedo, m_surfaceContributionEstimateBuffers->filteredScaledContribution); + m_denoiser->denoise(m_volumeContributionEstimateBuffers->scaledContribution, m_volumeContributionEstimateBuffers->normal, m_volumeContributionEstimateBuffers->albedo, m_volumeContributionEstimateBuffers->filteredScaledContribution); +#endif + +#ifdef USE_EMBREE_PARALLEL + embree::parallel_for(0, (int)numPixels, 1, [&](const embree::range &r) { + for (size_t pIdx = r.begin(); pIdx < r.end(); pIdx++) { +#else + tbb::parallel_for(tbb::blocked_range(0, numPixels), [&](tbb::blocked_range r) { + for (int pIdx = r.begin(); pIdx < r.end(); ++pIdx) { +#endif + + float pVolEst = m_filteredPVolBuffer[pIdx]; + pVolEst = std::max(0.f, std::min(1.f, pVolEst)); +#ifndef VSP_USE_PVOL_EST + // If we add zero samples to the other buffers (e.g., to the volume buffer when we have a surface sample) + // Then we do not need to multiply with (1.f -pVolEst) or pVolEst. + // Note for the second moment look for the USE_PVOL_CORRECTION earlier whne calcualting the sqrt of the second moment. + pgl_vec3f surfaceContribution = m_surfaceContributionEstimateBuffers->filteredContribution[pIdx]; + pgl_vec3f volumeContribution = m_volumeContributionEstimateBuffers->filteredContribution[pIdx]; +#else + // If the surface/volume buffers only include volume or surface samples we have + // to correct with (1.f -pVolEst) and pVolEst. + // Not since we already use the sqrt of the second moment we only need to multiply + // with pVolEst and not pVolEst°2 + + pgl_vec3f surfaceContribution, volumeContribution; +#ifndef VSP_DENOISE_AFTER_PRODUCT + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + surfaceContribution = (1.f - pVolEst) * m_surfaceContributionEstimateBuffers->filteredContribution[pIdx]; + volumeContribution = pVolEst * m_volumeContributionEstimateBuffers->filteredContribution[pIdx]; + } + else { + surfaceContribution.x = m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].x > 0.f ? (1.f - pVolEst) * std::sqrt(m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].x) : 0.f; + surfaceContribution.y = m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].y > 0.f ? (1.f - pVolEst) * std::sqrt(m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].y) : 0.f; + surfaceContribution.z = m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].z > 0.f ? (1.f - pVolEst) * std::sqrt(m_surfaceContributionEstimateBuffers->filteredContribution[pIdx].z) : 0.f; + + volumeContribution.x = m_volumeContributionEstimateBuffers->filteredContribution[pIdx].x > 0.f ? pVolEst * std::sqrt(m_volumeContributionEstimateBuffers->filteredContribution[pIdx].x) : 0.f; + volumeContribution.y = m_volumeContributionEstimateBuffers->filteredContribution[pIdx].y > 0.f ? pVolEst * std::sqrt(m_volumeContributionEstimateBuffers->filteredContribution[pIdx].y) : 0.f; + volumeContribution.z = m_volumeContributionEstimateBuffers->filteredContribution[pIdx].z > 0.f ? pVolEst * std::sqrt(m_volumeContributionEstimateBuffers->filteredContribution[pIdx].z) : 0.f; + } +#else + if (m_cfg.vspType == PGLVSPTypes::EContribution) { + surfaceContribution = m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx]; + volumeContribution = m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx]; + } + else { + surfaceContribution.x = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].x); + surfaceContribution.y = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].y); + surfaceContribution.z = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].z); + + volumeContribution.x = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].x); + volumeContribution.y = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].y); + volumeContribution.z = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].z); + } +#endif + +#endif + pgl_vec3f contribution = surfaceContribution + volumeContribution; + float contributionScalar = pglVec3fMax(contribution); + float volumeContributionScalar = pglVec3fMax(volumeContribution); + + m_vspContributionBuffer[pIdx] = contributionScalar > 0.f ? volumeContributionScalar / (contributionScalar) : -1.f; + } + }); + } +#endif m_ready = true; } void addSample(const pgl_point2i pixel, const PGLImageSpaceSample &sample) { std::size_t pixelIdx = pixel.y * m_resolution.x + pixel.x; - m_contributionEstimateBuffers->spp[pixelIdx] += 1; - float alpha = 1.f / m_contributionEstimateBuffers->spp[pixelIdx]; - - m_contributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->contribution[pixelIdx] + alpha * sample.contribution; - m_contributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; - m_contributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; - m_contributionEstimateBuffers->secondMoment[pixelIdx] = - (1.f - alpha) * m_contributionEstimateBuffers->secondMoment[pixelIdx] + alpha * (sample.contribution * sample.contribution); + if(m_cfg.contributionEstimate) { + m_contributionEstimateBuffers->spp[pixelIdx] += 1; + float alpha = 1.f / m_contributionEstimateBuffers->spp[pixelIdx]; + + const pgl_vec3f quantity = m_cfg.contributionType == PGLContributionTypes::EFirstMoment ? sample.contribution : sample.contribution*sample.contribution; + m_contributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->contribution[pixelIdx] + alpha * sample.contribution; + m_contributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; + m_contributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; + } +#if defined(OPENPGL_VSP_GUIDING) + if(m_cfg.vspEstimate) { + if (sample.IsSurfaceEvent()) { + m_surfaceContributionEstimateBuffers->spp[pixelIdx] += 1; +#ifdef VSP_USE_PVOL_EST + // calculating the alpha using only the number of surface samples + float alpha = 1.f / m_surfaceContributionEstimateBuffers->spp[pixelIdx]; +#else + // calculating the alpha simulating we added zero samples for each volume sample as well + float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); +#endif + pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; + m_surfaceContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; + m_surfaceContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; + m_surfaceContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; +#ifndef VSP_USE_PVOL_EST + // adding zero value samples to the volume buffer + m_volumeContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->contribution[pixelIdx]; +#endif + } else { + m_volumeContributionEstimateBuffers->spp[pixelIdx] += 1; +#ifdef VSP_USE_PVOL_EST + // calculating the alpha using only the number of volume samples + float alpha = 1.f / m_volumeContributionEstimateBuffers->spp[pixelIdx]; +#else + // calculating the alpha simulating we added zero samples for each surface sample as well + float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); +#endif + pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; + m_volumeContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; + m_volumeContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; + m_volumeContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; +#ifndef VSP_USE_PVOL_EST + // adding zero value samples to the surface buffer + m_surfaceContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->contribution[pixelIdx]; +#endif + } + } +#endif } - pgl_vec3f getContributionEstimate(const pgl_point2i pixel, const bool secondMoment = false) const + pgl_vec3f getContributionEstimate(const pgl_point2i pixel) const { + if(!m_ready || !m_cfg.contributionEstimate) { + return {0.f, 0.f, 0.f}; + } + std::size_t pixelIdx = pixel.y * m_resolution.x + pixel.x; - const pgl_vec3f c = !secondMoment ? m_contributionEstimateBuffers->filteredContribution[pixelIdx] : m_contributionEstimateBuffers->filteredSecondMoment[pixelIdx]; + const pgl_vec3f c = m_contributionEstimateBuffers->filteredContribution[pixelIdx]; return c; } +#if defined(OPENPGL_VSP_GUIDING) + float getVolumeScatterProbabilityEstimate(const pgl_point2i pixel) const + { + if (!m_ready || !m_cfg.vspEstimate) { + return 0.5f; + } + std::size_t pixelIdx = pixel.y * m_resolution.x + pixel.x; + return m_vspContributionBuffer[pixelIdx]; + } +#endif bool isReady() const { return m_ready; @@ -482,20 +815,56 @@ struct ImageSpaceGuidingBuffer void reset() { - if (m_contributionEstimateBuffers) + if (m_cfg.contributionEstimate && m_contributionEstimateBuffers) { m_contributionEstimateBuffers->reset(); } +#if defined(OPENPGL_VSP_GUIDING) + if(m_cfg.vspEstimate) { + if (m_surfaceContributionEstimateBuffers) + { + m_surfaceContributionEstimateBuffers->reset(); + } + if (m_volumeContributionEstimateBuffers) + { + m_volumeContributionEstimateBuffers->reset(); + } + const int numPixels = m_resolution.x * m_resolution.y; + +#ifdef USE_EMBREE_PARALLEL + embree::parallel_for(0, (int)numPixels, 1, [&](const embree::range &r) { + for (size_t pIdx = r.begin(); pIdx < r.end(); pIdx++) +#else + tbb::parallel_for(tbb::blocked_range(0, numPixels), [&](tbb::blocked_range r) { + for (int pIdx = r.begin(); pIdx < r.end(); ++pIdx) +#endif + { + m_pVolBuffer[pIdx] = 0.f; + m_filteredPVolBuffer[pIdx] = 0.f; + m_vspContributionBuffer[pIdx] = 0.f; + } + }); + } +#endif m_ready = false; } private: bool m_ready{false}; - bool m_useSecondMoment{false}; + PGLImageSpaceGuidingBufferConfig m_cfg; pgl_point2i m_resolution{0, 0}; Denoiser *m_denoiser{nullptr}; Buffers *m_contributionEstimateBuffers{nullptr}; + +#if defined(OPENPGL_VSP_GUIDING) + Buffers *m_surfaceContributionEstimateBuffers{nullptr}; + Buffers *m_volumeContributionEstimateBuffers{nullptr}; + + float *m_pVolBuffer {nullptr}; + float *m_filteredPVolBuffer {nullptr}; + float *m_vspContributionBuffer {nullptr}; +#endif }; } // namespace openpgl \ No newline at end of file diff --git a/openpgl/include/openpgl/common.h b/openpgl/include/openpgl/common.h index 40b21b03..ab0e74ec 100644 --- a/openpgl/include/openpgl/common.h +++ b/openpgl/include/openpgl/common.h @@ -178,6 +178,16 @@ inline void pglVec3fMultiply(pgl_vec3f &veca, const pgl_vec3f &vecb) veca.z *= vecb.z; } +inline float pglVec3fMax(const pgl_vec3f &vec) +{ + return std::max(vec.x, std::max(vec.y, vec.z)); +} + +inline float pglVec3fMin(const pgl_vec3f &vec) +{ + return std::min(vec.x, std::min(vec.y, vec.z)); +} + inline void pglVec2f(pgl_vec2f &vec, const float x, const float y) { vec.x = x; diff --git a/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h b/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h index d468602a..6be3485b 100644 --- a/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h +++ b/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h @@ -25,6 +25,57 @@ namespace util */ struct ImageSpaceGuidingBuffer { + struct Config { + + Config(Point2i resolution) { + data.resolution = {resolution.x, resolution.y}; + } + + void EnableContributionEstimate(const bool contributionEstimate) + { + data.contributionEstimate = contributionEstimate; + } + + bool ContributionEstimate() const { + return data.contributionEstimate; + } + + Point2i GetResolution() const { + return {data.resolution.x, data.resolution.y}; + } + + void SetContributionType(PGLContributionTypes type) { + data.contributionType = type; + } + + PGLContributionTypes GetContributionType() { + return data.contributionType; + } + +#if defined(OPENPGL_VSP_GUIDING) + void EnableVolumeScatterProbabilityEstimate(const bool vspEstimate) + { + data.vspEstimate = vspEstimate; + } + + bool VolumeScatterProbabilityEstimate() const { + return data.vspEstimate; + } + + void SetVolumeScatterProbabilityType(PGLVSPTypes type) { + data.vspType = type; + } + + PGLVSPTypes GetVolumeScatterProbabilityType() { + return data.vspType; + } +#endif + friend struct ImageSpaceGuidingBuffer; + private: + PGLImageSpaceGuidingBufferConfig data; + }; + + typedef PGLImageSpaceSample Sample; /** @@ -32,7 +83,7 @@ struct ImageSpaceGuidingBuffer * * @param resolution The size/reslution of the image buffer */ - ImageSpaceGuidingBuffer(const Point2i resolution); + ImageSpaceGuidingBuffer(const Config cfg); /** * Creates/Loads an ImageSpaceGuidingBuffer from multi-channel EXR file. @@ -71,7 +122,11 @@ struct ImageSpaceGuidingBuffer * * This quantity is usefull guided/adjoint-driven Russina roulette decisions. */ - Vector3f GetPixelContributionEstimate(const Point2i pixel) const; + Vector3f GetContributionEstimate(const Point2i pixel) const; + +#if defined(OPENPGL_VSP_GUIDING) + float GetVolumeScatterProbabilityEstimate(const Point2i pixel) const; +#endif /** * @brief If the image-space guiding buffer is ready and can be used. @@ -92,9 +147,9 @@ struct ImageSpaceGuidingBuffer /// Implementation //////////////////////////////////////////////////////////// -OPENPGL_INLINE ImageSpaceGuidingBuffer::ImageSpaceGuidingBuffer(const Point2i resolution) +OPENPGL_INLINE ImageSpaceGuidingBuffer::ImageSpaceGuidingBuffer(const Config cfg) { - m_imageSpaceGuidingBufferHandle = pglFieldNewImageSpaceGuidingBuffer(resolution); + m_imageSpaceGuidingBufferHandle = pglFieldNewImageSpaceGuidingBuffer(cfg.data); } OPENPGL_INLINE ImageSpaceGuidingBuffer::ImageSpaceGuidingBuffer(const std::string &fileName) @@ -128,11 +183,19 @@ OPENPGL_INLINE void ImageSpaceGuidingBuffer::Store(const std::string &fileName) pglImageSpaceGuidingBufferStore(m_imageSpaceGuidingBufferHandle, fileName.c_str()); } -OPENPGL_INLINE Vector3f ImageSpaceGuidingBuffer::GetPixelContributionEstimate(const Point2i pixel) const +OPENPGL_INLINE Vector3f ImageSpaceGuidingBuffer::GetContributionEstimate(const Point2i pixel) const +{ + OPENPGL_ASSERT(m_imageSpaceGuidingBufferHandle); + return pglImageSpaceGuidingBufferGetContributionEstimate(m_imageSpaceGuidingBufferHandle, pixel); +} + +#if defined(OPENPGL_VSP_GUIDING) +OPENPGL_INLINE float ImageSpaceGuidingBuffer::GetVolumeScatterProbabilityEstimate(const Point2i pixel) const { OPENPGL_ASSERT(m_imageSpaceGuidingBufferHandle); - return pglImageSpaceGuidingBufferGetPixelContributionEstimate(m_imageSpaceGuidingBufferHandle, pixel); + return pglImageSpaceGuidingBufferGetVolumeScatterProbabilityEstimate(m_imageSpaceGuidingBufferHandle, pixel); } +#endif OPENPGL_INLINE bool ImageSpaceGuidingBuffer::IsReady() const { diff --git a/openpgl/include/openpgl/data.h b/openpgl/include/openpgl/data.h index cb6cb02e..d35d6025 100644 --- a/openpgl/include/openpgl/data.h +++ b/openpgl/include/openpgl/data.h @@ -165,7 +165,7 @@ struct PGLImageSpaceSample void SetSurfaceEvent(bool isSurfaceEvent) { if (isSurfaceEvent) - flags ^= EVolumeEvent; + flags &= ~EVolumeEvent; else flags |= EVolumeEvent; } @@ -173,11 +173,33 @@ struct PGLImageSpaceSample /// @brief If the samples originates from a surface event. bool IsSurfaceEvent() const { - return flags ^ EVolumeEvent; + return !(flags & EVolumeEvent); } #endif }; +enum PGLContributionTypes { + EFirstMoment = 0, + ESecondMoment, +}; + +enum PGLVSPTypes +{ + EContribution = 0, + EVariance, +}; + +struct PGLImageSpaceGuidingBufferConfig { + pgl_point2i resolution {0, 0}; + bool contributionEstimate {true}; + PGLContributionTypes contributionType {PGLContributionTypes::EFirstMoment}; + //float maxContributionValue {FLT_MAX}; //TODO +#if defined(OPENPGL_VSP_GUIDING) + bool vspEstimate {false}; + PGLVSPTypes vspType {PGLVSPTypes::EContribution}; +#endif +}; + #endif struct PGLString diff --git a/openpgl/include/openpgl/imagespaceguidingbuffer.h b/openpgl/include/openpgl/imagespaceguidingbuffer.h index 0316618d..8bf692f2 100644 --- a/openpgl/include/openpgl/imagespaceguidingbuffer.h +++ b/openpgl/include/openpgl/imagespaceguidingbuffer.h @@ -19,7 +19,7 @@ typedef ManagedObject ImageSpaceGuidingBuffer; typedef ImageSpaceGuidingBuffer *PGLImageSpaceGuidingBuffer; - OPENPGL_CORE_INTERFACE PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBuffer(const pgl_point2i resolution); + OPENPGL_CORE_INTERFACE PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBuffer(const PGLImageSpaceGuidingBufferConfig cfg); OPENPGL_CORE_INTERFACE PGLImageSpaceGuidingBuffer pglFieldNewImageSpaceGuidingBufferFromFile(const char *fileName); @@ -31,8 +31,10 @@ typedef ManagedObject ImageSpaceGuidingBuffer; OPENPGL_CORE_INTERFACE void pglImageSpaceGuidingBufferStore(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const char *fileName); - OPENPGL_CORE_INTERFACE pgl_vec3f pglImageSpaceGuidingBufferGetPixelContributionEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel); - + OPENPGL_CORE_INTERFACE pgl_vec3f pglImageSpaceGuidingBufferGetContributionEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel); +#if defined(OPENPGL_VSP_GUIDING) + OPENPGL_CORE_INTERFACE float pglImageSpaceGuidingBufferGetVolumeScatterProbabilityEstimate(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer, const pgl_point2i pixel); +#endif OPENPGL_CORE_INTERFACE bool pglImageSpaceGuidingBufferIsReady(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer); OPENPGL_CORE_INTERFACE void pglImageSpaceGuidingBufferReset(PGLImageSpaceGuidingBuffer imageSpaceGuidingBuffer); From da511bdb3460393624970733f7cb0b0eacc64be3 Mon Sep 17 00:00:00 2001 From: Fiona730 Date: Wed, 8 Jan 2025 21:25:35 +0100 Subject: [PATCH 07/15] [vsp] cleanup and minor bugfixing --- openpgl/imagespace/ImageSpaceGuidingBuffer.h | 36 +++---------------- .../openpgl/cpp/ImageSpaceGuidingBuffer.h | 4 +-- 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/openpgl/imagespace/ImageSpaceGuidingBuffer.h b/openpgl/imagespace/ImageSpaceGuidingBuffer.h index 2f2822fe..ae07c3c1 100644 --- a/openpgl/imagespace/ImageSpaceGuidingBuffer.h +++ b/openpgl/imagespace/ImageSpaceGuidingBuffer.h @@ -25,7 +25,6 @@ #define TINYEXR_IMPLEMENTATION #include -//#define VSP_DENOISE_AFTER_PRODUCT #define VSP_USE_PVOL_EST namespace openpgl @@ -148,8 +147,8 @@ struct ImageSpaceGuidingBuffer m_cfg.contributionEstimate = false; m_cfg.contributionType = PGLContributionTypes::EFirstMoment; #if defined(OPENPGL_VSP_GUIDING) - m_cfg.contributionEstimate = false; - m_cfg.contributionType = PGLContributionTypes::EFirstMoment; + m_cfg.vspEstimate = false; + m_cfg.vspType = PGLVSPTypes::EContribution; #endif for (int i = 0; i < layer_names.size(); i++) { std::string layerName = layer_names[i]; @@ -165,7 +164,7 @@ struct ImageSpaceGuidingBuffer { m_cfg.vspEstimate = true; if(layerName == "surfContrib2nd") { - m_cfg.vspType = PGLVSPTypes::EContribution; + m_cfg.vspType = PGLVSPTypes::EVariance; } } #endif @@ -651,22 +650,12 @@ struct ImageSpaceGuidingBuffer const float volumeSampleCount = m_volumeContributionEstimateBuffers->spp[pIdx]; const float pVolEst = volumeSampleCount / (surfaceSampleCount + volumeSampleCount); m_pVolBuffer[pIdx] = pVolEst; -#ifdef VSP_DENOISE_AFTER_PRODUCT - m_surfaceContributionEstimateBuffers->scaledContribution[pIdx] = m_surfaceContributionEstimateBuffers->contribution[pIdx] * (1 - pVolEst); - m_volumeContributionEstimateBuffers->scaledContribution[pIdx] = m_volumeContributionEstimateBuffers->contribution[pIdx] * pVolEst; -#endif } }); m_denoiser->denoise(m_pVolBuffer, m_filteredPVolBuffer); - -#ifndef VSP_DENOISE_AFTER_PRODUCT m_denoiser->denoise(m_surfaceContributionEstimateBuffers->contribution, m_surfaceContributionEstimateBuffers->normal, m_surfaceContributionEstimateBuffers->albedo, m_surfaceContributionEstimateBuffers->filteredContribution); m_denoiser->denoise(m_volumeContributionEstimateBuffers->contribution, m_volumeContributionEstimateBuffers->normal, m_volumeContributionEstimateBuffers->albedo, m_volumeContributionEstimateBuffers->filteredContribution); -#else - m_denoiser->denoise(m_surfaceContributionEstimateBuffers->scaledContribution, m_surfaceContributionEstimateBuffers->normal, m_surfaceContributionEstimateBuffers->albedo, m_surfaceContributionEstimateBuffers->filteredScaledContribution); - m_denoiser->denoise(m_volumeContributionEstimateBuffers->scaledContribution, m_volumeContributionEstimateBuffers->normal, m_volumeContributionEstimateBuffers->albedo, m_volumeContributionEstimateBuffers->filteredScaledContribution); -#endif #ifdef USE_EMBREE_PARALLEL embree::parallel_for(0, (int)numPixels, 1, [&](const embree::range &r) { @@ -691,7 +680,6 @@ struct ImageSpaceGuidingBuffer // with pVolEst and not pVolEst°2 pgl_vec3f surfaceContribution, volumeContribution; -#ifndef VSP_DENOISE_AFTER_PRODUCT if (m_cfg.vspType == PGLVSPTypes::EContribution) { surfaceContribution = (1.f - pVolEst) * m_surfaceContributionEstimateBuffers->filteredContribution[pIdx]; volumeContribution = pVolEst * m_volumeContributionEstimateBuffers->filteredContribution[pIdx]; @@ -705,21 +693,6 @@ struct ImageSpaceGuidingBuffer volumeContribution.y = m_volumeContributionEstimateBuffers->filteredContribution[pIdx].y > 0.f ? pVolEst * std::sqrt(m_volumeContributionEstimateBuffers->filteredContribution[pIdx].y) : 0.f; volumeContribution.z = m_volumeContributionEstimateBuffers->filteredContribution[pIdx].z > 0.f ? pVolEst * std::sqrt(m_volumeContributionEstimateBuffers->filteredContribution[pIdx].z) : 0.f; } -#else - if (m_cfg.vspType == PGLVSPTypes::EContribution) { - surfaceContribution = m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx]; - volumeContribution = m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx]; - } - else { - surfaceContribution.x = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].x); - surfaceContribution.y = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].y); - surfaceContribution.z = std::sqrt(m_surfaceContributionEstimateBuffers->filteredScaledContribution[pIdx].z); - - volumeContribution.x = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].x); - volumeContribution.y = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].y); - volumeContribution.z = std::sqrt(m_volumeContributionEstimateBuffers->filteredScaledContribution[pIdx].z); - } -#endif #endif pgl_vec3f contribution = surfaceContribution + volumeContribution; @@ -730,7 +703,7 @@ struct ImageSpaceGuidingBuffer } }); } -#endif + m_ready = true; } @@ -757,7 +730,6 @@ struct ImageSpaceGuidingBuffer // calculating the alpha simulating we added zero samples for each volume sample as well float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); #endif - pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; m_surfaceContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; m_surfaceContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; m_surfaceContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; diff --git a/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h b/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h index 6be3485b..1c90d05b 100644 --- a/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h +++ b/openpgl/include/openpgl/cpp/ImageSpaceGuidingBuffer.h @@ -19,8 +19,8 @@ namespace util * @brief The ImageSpaceGuidingBuffer class calculates image-space guiding information from pixel samples. * * The class collects and stores the Monte-Carlo random work pixels samples generated during rendering. - * The information gathered by these samples is then used, duting the @ref Update step to calculate/estimate - * image-space guiding information (e.g., pixel contribtuion estimates for guided/adjoint-driven RR). + * The information gathered by these samples is then used, during the @ref Update step to calculate/estimate + * image-space guiding information (e.g., pixel contribution estimates for guided/adjoint-driven RR). * */ struct ImageSpaceGuidingBuffer From 6f41377b6a8ebf5bb13e71db911280b299131e6f Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Wed, 30 Jul 2025 16:31:02 +0200 Subject: [PATCH 08/15] [vsp] Fixing the cleanup --- openpgl/imagespace/ImageSpaceGuidingBuffer.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpgl/imagespace/ImageSpaceGuidingBuffer.h b/openpgl/imagespace/ImageSpaceGuidingBuffer.h index ae07c3c1..e090dcd9 100644 --- a/openpgl/imagespace/ImageSpaceGuidingBuffer.h +++ b/openpgl/imagespace/ImageSpaceGuidingBuffer.h @@ -703,7 +703,7 @@ struct ImageSpaceGuidingBuffer } }); } - +#endif m_ready = true; } @@ -730,6 +730,7 @@ struct ImageSpaceGuidingBuffer // calculating the alpha simulating we added zero samples for each volume sample as well float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); #endif + pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; m_surfaceContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; m_surfaceContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; m_surfaceContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; From 47ae97c7eaaac0839c9923da8de8a590e81eafed Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Thu, 31 Jul 2025 14:57:32 +0200 Subject: [PATCH 09/15] [release] Preparing version bump to 0.8.0 --- .github/workflows/main.yml | 10 +++++----- CMakeLists.txt | 8 ++++---- README.md | 4 ++-- doc/changelog_latest.md | 2 +- doc/changelog_previous.md | 8 ++++++++ 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4c0f312b..f8e0eb78 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -193,7 +193,7 @@ jobs: with: image: rockylinux:8.7 cmd: | - export OPENPGL_RELEASE_PACKAGE_VERSION=0.7.1 + export OPENPGL_RELEASE_PACKAGE_VERSION=0.8.0 scripts/release/linux.sh artifact-out: release-linux artifact-path: ./openpgl*.gz @@ -207,8 +207,8 @@ jobs: artifact-out: release-windows artifact-path: ./openpgl*.zip cmd: | - $env:OPENPGL_RELEASE_PACKAGE_VERSION="0.7.1" - $OPENPGL_RELEASE_PACKAGE_VERSION="0.7.1" + $env:OPENPGL_RELEASE_PACKAGE_VERSION="0.8.0" + $OPENPGL_RELEASE_PACKAGE_VERSION="0.8.0" scripts/release/windows.ps1 "Visual Studio 15 2017 Win64" "v141" release-macos: @@ -220,7 +220,7 @@ jobs: artifact-out: release-macos artifact-path: ./*.zip cmd: | - export OPENPGL_RELEASE_PACKAGE_VERSION="0.7.1" + export OPENPGL_RELEASE_PACKAGE_VERSION="0.8.0" scripts/release/macos.sh #release-macos-arm: @@ -232,7 +232,7 @@ jobs: # artifact-out: release-macos-arm # artifact-path: ./*.zip # cmd: | - # export OPENPGL_RELEASE_PACKAGE_VERSION="0.7.1" + # export OPENPGL_RELEASE_PACKAGE_VERSION="0.8.0" # scripts/release/macos.sh -DBUILD_TBB_FROM_SOURCE=ON ## Binary Scan Jobs ## diff --git a/CMakeLists.txt b/CMakeLists.txt index c61d2de3..ea1341ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ include(GNUInstallDirs) ## Establish project ## -project(openpgl VERSION 0.7.1 LANGUAGES C CXX) +project(openpgl VERSION 0.8.0 LANGUAGES C CXX) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) include(openpgl_macros) @@ -51,9 +51,9 @@ option(OPENPGL_BUILD_CHECK_TOOL "Build check tool application." OFF) try_compile(COMPILER_SUPPORTS_ARM_NEON "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/cmake/check_arm_neon.cpp") -OPTION(OPENPGL_EF_RADIANCE_CACHES "Enables experimental feature (ir)radiance caches." OFF) -OPTION(OPENPGL_EF_VSP_GUIDING "Enables experimental feature volume scatter probability guiding." OFF) -OPTION(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER "Enables experimental feature ImageSpaceGuidignBuffer." OFF) +OPTION(OPENPGL_EF_RADIANCE_CACHES "Enables experimental feature (ir)radiance caches." ON) +OPTION(OPENPGL_EF_VSP_GUIDING "Enables experimental feature volume scatter probability guiding." ON) +OPTION(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER "Enables experimental feature ImageSpaceGuidignBuffer." ON) OPTION(OPENPGL_DIRECTION_COMPRESSION "Using 32-Bit compression to represent directions." OFF) OPTION(OPENPGL_RADIANCE_COMPRESSION "Using RGBE 32-Bit compression to represent radiance data (linear RGB)." OFF) diff --git a/README.md b/README.md index ca330aea..9f400ec7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Intel® Open Path Guiding Library -This is release v0.7.1 of Intel® Open PGL. For changes and new features, +This is release v0.8.0 of Intel® Open PGL. For changes and new features, see the [changelog](CHANGELOG.md). Visit http://www.openpgl.org for more information. @@ -236,7 +236,7 @@ To make CMake aware of Open PGL’s CMake configuration scripts the `openpgl_DIR` has to be set to their location during configuration: ``` bash -cmake -Dopenpgl_DIR=[openpgl_install]/lib/cmake/openpgl-0.7.1 .. +cmake -Dopenpgl_DIR=[openpgl_install]/lib/cmake/openpgl-0.8.0 .. ``` After that, adding OpenPGL to a CMake project/target is done by first diff --git a/doc/changelog_latest.md b/doc/changelog_latest.md index 1718fafb..375af45c 100644 --- a/doc/changelog_latest.md +++ b/doc/changelog_latest.md @@ -1,4 +1,4 @@ -## Open PGL 0.7.1 +## Open PGL 0.8.0 - Bugfixes: - Fixing invalidation of the guiding field on initial creation if a cell contains no samples [#23](https://github.com/RenderKit/openpgl/issues/23). diff --git a/doc/changelog_previous.md b/doc/changelog_previous.md index c0996193..c4bdfbdc 100644 --- a/doc/changelog_previous.md +++ b/doc/changelog_previous.md @@ -1,3 +1,11 @@ +## Open PGL 0.7.1 + +- Bugfixes: + - Fixing invalidation of the guiding field on initial creation if a cell contains no samples [#23](https://github.com/RenderKit/openpgl/issues/23). + - Fixing noisy stdout printouts [#19](https://github.com/RenderKit/openpgl/issues/19). + - Improving robustness of the integer arithmetric used during the deterministic multi-threaded building of the spatial subdivision structure. + - Improving numerical stability of fitting process of the VMM-based guiding models. + ## Open PGL 0.7.0 - New (**Experimental**) Features: From 29f3ff3db3ab1f925c199b590f93b9175e8f38f9 Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Thu, 31 Jul 2025 18:03:10 +0200 Subject: [PATCH 10/15] [cleanup] Removing leftover print outs --- openpgl/imagespace/ImageSpaceGuidingBuffer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpgl/imagespace/ImageSpaceGuidingBuffer.h b/openpgl/imagespace/ImageSpaceGuidingBuffer.h index e090dcd9..eace5184 100644 --- a/openpgl/imagespace/ImageSpaceGuidingBuffer.h +++ b/openpgl/imagespace/ImageSpaceGuidingBuffer.h @@ -170,14 +170,12 @@ struct ImageSpaceGuidingBuffer #endif } - std::cout << "m_cfg.contributionEstimate = " << m_cfg.contributionEstimate << std::endl; if (m_cfg.contributionEstimate) { m_contributionEstimateBuffers = new Buffers(m_resolution); } m_cfg.resolution = m_resolution; #if defined(OPENPGL_VSP_GUIDING) - std::cout << "m_cfg.vspEstimate = " << m_cfg.vspEstimate << std::endl; if(m_cfg.vspEstimate) { m_surfaceContributionEstimateBuffers = new Buffers(m_resolution); m_volumeContributionEstimateBuffers = new Buffers(m_resolution); From 5c66f2a8a695f0f513c73bd97f408ab6f99c8930 Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Tue, 19 Aug 2025 13:53:33 +0200 Subject: [PATCH 11/15] [vsp] Adding missing define wrapper. --- openpgl/include/openpgl/cpp/FieldConfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpgl/include/openpgl/cpp/FieldConfig.h b/openpgl/include/openpgl/cpp/FieldConfig.h index 956d5efe..7264aa92 100644 --- a/openpgl/include/openpgl/cpp/FieldConfig.h +++ b/openpgl/include/openpgl/cpp/FieldConfig.h @@ -59,9 +59,9 @@ struct FieldConfig * @param useKnnIsLookup if distance based importance sampling of the neighbors should be used */ void SetUseKnnIsLookup(const bool useKnnIsLookup); - +#ifdef OPENPGL_VSP_GUIDING void SetVarianceBasedVSP(const bool varianceBasedVSP); - +#endif /** * @brief For debugging and benchmarking the update of the spatial structure this function can disable * the training of the directional distribution during the update iterations. From a5adcad91946528d36c1735e80f213eccf3449fe Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Tue, 19 Aug 2025 13:53:53 +0200 Subject: [PATCH 12/15] [doc] Fixing some typos --- doc/changelog_previous.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/changelog_previous.md b/doc/changelog_previous.md index c4bdfbdc..5d7403a1 100644 --- a/doc/changelog_previous.md +++ b/doc/changelog_previous.md @@ -3,7 +3,7 @@ - Bugfixes: - Fixing invalidation of the guiding field on initial creation if a cell contains no samples [#23](https://github.com/RenderKit/openpgl/issues/23). - Fixing noisy stdout printouts [#19](https://github.com/RenderKit/openpgl/issues/19). - - Improving robustness of the integer arithmetric used during the deterministic multi-threaded building of the spatial subdivision structure. + - Improving robustness of the integer arithmetic used during the deterministic multi-threaded building of the spatial subdivision structure. - Improving numerical stability of fitting process of the VMM-based guiding models. ## Open PGL 0.7.0 @@ -22,7 +22,7 @@ - API changes: - `pgl_direction`: A new **wrapper** type for directional data. When using C++ `pgl_direction` can directly be assigned by and to `pgl_vec3f`. - - `pgl_spectrum`: A new **wrapper** type for spetral (i.e., linear RGB) data. When using C++ `pgl_spectrum` can directly be assigned by and to `pgl_vec3f`. + - `pgl_spectrum`: A new **wrapper** type for spectral (i.e., linear RGB) data. When using C++ `pgl_spectrum` can directly be assigned by and to `pgl_vec3f`. - `SampleData`: - New enum `EDirectLight` flag that identifies if the radiance stored in this sample comes directly from an emitter (e.g., emissive surface, volume, or light source). - `direction`: Changes the type `pgl_vec3f` to `pgl_direction`. @@ -63,18 +63,18 @@ -`AddSample`: Add a pixel sample of type `ImageSpaceGuidingBuffer::Sample` to the buffer. - `Update`: Updates the image-space guiding information/approximations from the previously collected samples (e.g., denoises the pixel contribution estimates using OIDN). For efficiency reasons, it makes sense not to update the buffer after every rendering progression but in an exponential fashion (e.g., at progression `2^0`,`2^1`,...,`2^N`). - `IsReady`: If the ISGB is ready (i.e., at least one `Update` step was performed). - - `GetPixelContributionEstimate`: Returns the pixel contibution estimate for a given pixel, which can be used, for example, for guided RR. + - `GetPixelContributionEstimate`: Returns the pixel contribution estimate for a given pixel, which can be used, for example, for guided RR. - `Reset`: Resets the ISGB. - `ImageSpaceGuidingBuffer::Sample`: This structure is used to store information about a per-pixel sample that is passed to the ISGB. - `contribution`: The contribution estimate of the pixel value of a given sample (type `pgl_vec3f`). - `albedo`: The albedo of the surface or the volume at the first scattering event (type `pgl_vec3f`). - - `normal`: The normal at the first surface scattering event or the ray dairection towards the camers if the first event is a volume event (type `pgl_vec3f`). + - `normal`: The normal at the first surface scattering event or the ray direction towards the cameras if the first event is a volume event (type `pgl_vec3f`). - `flags`: Bit encoded information about the sample (e.g., if the first scattering event is a volume event `Sample::EVolumeEvent`). - Optimizations: - Compression for spectral and directional: - To reduce the size of the `SampleData` and `ZeroValueSampleData` data types it is possible to enable 32-Bit compression, which is mainly adviced when enabling the RC feature via `OPENPGL_EF_RADIANCE_CACHES=ON`. + To reduce the size of the `SampleData` and `ZeroValueSampleData` data types it is possible to enable 32-Bit compression, which is mainly advised when enabling the RC feature via `OPENPGL_EF_RADIANCE_CACHES=ON`. - `OPENPGL_DIRECTION_COMPRESSION`: Enables 32-Bit compression for `pgl_direction`. - `OPENPGL_RADIANCE_COMPRESSION`: Enables 32-Bit compression for `pgl_spectrum`. - Bugfixes: @@ -88,7 +88,7 @@ - Api changes: - `Device` added `numThread` parameter (default = 0) to the constructor to set the number of threads used by `Open PGL` during training. The default value of `0` uses all threads provided by `TBB`. If the renderer uses `TBB` as well and regulates the thread count this count is also used by `Open PGL`. - `SurfaceSamplingDistribution` and `VolumeSamplingDistribution`: - - Added `GetId` function to return the unique id of the spatial structure used to query the sampling distriubtion. + - Added `GetId` function to return the unique id of the spatial structure used to query the sampling distribution. - `Field` and `SampleStorage`, added `Compare` function to check if the data stored in different instances (e.g., generated by two separate runs) are similar (i.e., same spatial subdivisions and directional distributions). - `Field`: - The constructor of the `Field` class now takes a `FieldConfig` instead of a `PGLFieldArguments` object. **(BREAKING API CHANGE)** From 3434d0afe5f7fb60a9e87edfbcfcc0d5f0ba76cc Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Tue, 19 Aug 2025 13:54:33 +0200 Subject: [PATCH 13/15] [vsp] Changing the enum names for the Contribution and VSP buffers. --- openpgl/imagespace/ImageSpaceGuidingBuffer.h | 28 ++++++++++---------- openpgl/include/openpgl/data.h | 12 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/openpgl/imagespace/ImageSpaceGuidingBuffer.h b/openpgl/imagespace/ImageSpaceGuidingBuffer.h index eace5184..58a4c86f 100644 --- a/openpgl/imagespace/ImageSpaceGuidingBuffer.h +++ b/openpgl/imagespace/ImageSpaceGuidingBuffer.h @@ -145,10 +145,10 @@ struct ImageSpaceGuidingBuffer // identify config based on the stored layers m_cfg.contributionEstimate = false; - m_cfg.contributionType = PGLContributionTypes::EFirstMoment; + m_cfg.contributionType = PGLContributionTypes::EContribContribution; #if defined(OPENPGL_VSP_GUIDING) m_cfg.vspEstimate = false; - m_cfg.vspType = PGLVSPTypes::EContribution; + m_cfg.vspType = PGLVSPTypes::EVSPContribution; #endif for (int i = 0; i < layer_names.size(); i++) { std::string layerName = layer_names[i]; @@ -156,7 +156,7 @@ struct ImageSpaceGuidingBuffer { m_cfg.contributionEstimate = true; if(layerName == "Contrib2nd") { - m_cfg.contributionType = PGLContributionTypes::ESecondMoment; + m_cfg.contributionType = PGLContributionTypes::EContribVariance; } } #if defined(OPENPGL_VSP_GUIDING) @@ -164,7 +164,7 @@ struct ImageSpaceGuidingBuffer { m_cfg.vspEstimate = true; if(layerName == "surfContrib2nd") { - m_cfg.vspType = PGLVSPTypes::EVariance; + m_cfg.vspType = PGLVSPTypes::EVSPVariance; } } #endif @@ -371,7 +371,7 @@ struct ImageSpaceGuidingBuffer int cIdx = 0; if(m_cfg.contributionEstimate) { cIdx = layerChannels.size(); - if (m_cfg.contributionType == PGLContributionTypes::EFirstMoment) { + if (m_cfg.contributionType == PGLContributionTypes::EContribContribution) { layerChannels.emplace_back(cIdx, "Contrib"); } else { layerChannels.emplace_back(cIdx, "Contrib2nd"); @@ -385,7 +385,7 @@ struct ImageSpaceGuidingBuffer channelValues.emplace_back((const float *)m_contributionEstimateBuffers->spp); cIdx = layerChannels.size(); - if (m_cfg.contributionType == PGLContributionTypes::EFirstMoment) { + if (m_cfg.contributionType == PGLContributionTypes::EContribContribution) { layerChannels.emplace_back(cIdx, "ContribRaw"); } else { layerChannels.emplace_back(cIdx, "Contrib2ndRaw"); @@ -406,7 +406,7 @@ struct ImageSpaceGuidingBuffer #if defined(OPENPGL_VSP_GUIDING) if(m_cfg.vspEstimate) { cIdx = layerChannels.size(); - if (m_cfg.vspType == PGLVSPTypes::EContribution) { + if (m_cfg.vspType == PGLVSPTypes::EVSPContribution) { layerChannels.emplace_back(cIdx, "surfContrib"); } else { layerChannels.emplace_back(cIdx, "surfContrib2nd"); @@ -420,7 +420,7 @@ struct ImageSpaceGuidingBuffer channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->spp); cIdx = layerChannels.size(); - if (m_cfg.vspType == PGLVSPTypes::EContribution) { + if (m_cfg.vspType == PGLVSPTypes::EVSPContribution) { layerChannels.emplace_back(cIdx, "surfContribRaw"); } else { layerChannels.emplace_back(cIdx, "surfContrib2ndRaw"); @@ -439,7 +439,7 @@ struct ImageSpaceGuidingBuffer channelValues.emplace_back((const float *)m_surfaceContributionEstimateBuffers->normal); cIdx = layerChannels.size(); - if (m_cfg.vspType == PGLVSPTypes::EContribution) { + if (m_cfg.vspType == PGLVSPTypes::EVSPContribution) { layerChannels.emplace_back(cIdx, "volContrib"); } else { layerChannels.emplace_back(cIdx, "volContrib2nd"); @@ -453,7 +453,7 @@ struct ImageSpaceGuidingBuffer channelValues.emplace_back((const float *)m_volumeContributionEstimateBuffers->spp); cIdx = layerChannels.size(); - if (m_cfg.vspType == PGLVSPTypes::EContribution) { + if (m_cfg.vspType == PGLVSPTypes::EVSPContribution) { layerChannels.emplace_back(cIdx, "volContribRaw"); } else { layerChannels.emplace_back(cIdx, "volContrib2ndRaw"); @@ -678,7 +678,7 @@ struct ImageSpaceGuidingBuffer // with pVolEst and not pVolEst°2 pgl_vec3f surfaceContribution, volumeContribution; - if (m_cfg.vspType == PGLVSPTypes::EContribution) { + if (m_cfg.vspType == PGLVSPTypes::EVSPContribution) { surfaceContribution = (1.f - pVolEst) * m_surfaceContributionEstimateBuffers->filteredContribution[pIdx]; volumeContribution = pVolEst * m_volumeContributionEstimateBuffers->filteredContribution[pIdx]; } @@ -712,7 +712,7 @@ struct ImageSpaceGuidingBuffer m_contributionEstimateBuffers->spp[pixelIdx] += 1; float alpha = 1.f / m_contributionEstimateBuffers->spp[pixelIdx]; - const pgl_vec3f quantity = m_cfg.contributionType == PGLContributionTypes::EFirstMoment ? sample.contribution : sample.contribution*sample.contribution; + const pgl_vec3f quantity = m_cfg.contributionType == PGLContributionTypes::EContribContribution ? sample.contribution : sample.contribution*sample.contribution; m_contributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->contribution[pixelIdx] + alpha * sample.contribution; m_contributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; m_contributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_contributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; @@ -728,7 +728,7 @@ struct ImageSpaceGuidingBuffer // calculating the alpha simulating we added zero samples for each volume sample as well float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); #endif - pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; + pgl_vec3f quantity = m_cfg.vspType == EVSPVariance ? sample.contribution * sample.contribution : sample.contribution; m_surfaceContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; m_surfaceContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; m_surfaceContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_surfaceContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; @@ -745,7 +745,7 @@ struct ImageSpaceGuidingBuffer // calculating the alpha simulating we added zero samples for each surface sample as well float alpha = 1.f / (m_surfaceContributionEstimateBuffers->spp[pixelIdx] + m_volumeContributionEstimateBuffers->spp[pixelIdx]); #endif - pgl_vec3f quantity = m_cfg.vspType == EVariance ? sample.contribution * sample.contribution : sample.contribution; + pgl_vec3f quantity = m_cfg.vspType == EVSPVariance ? sample.contribution * sample.contribution : sample.contribution; m_volumeContributionEstimateBuffers->contribution[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->contribution[pixelIdx] + alpha * quantity; m_volumeContributionEstimateBuffers->albedo[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->albedo[pixelIdx] + alpha * sample.albedo; m_volumeContributionEstimateBuffers->normal[pixelIdx] = (1.f - alpha) * m_volumeContributionEstimateBuffers->normal[pixelIdx] + alpha * sample.normal; diff --git a/openpgl/include/openpgl/data.h b/openpgl/include/openpgl/data.h index d35d6025..14bddd04 100644 --- a/openpgl/include/openpgl/data.h +++ b/openpgl/include/openpgl/data.h @@ -179,24 +179,24 @@ struct PGLImageSpaceSample }; enum PGLContributionTypes { - EFirstMoment = 0, - ESecondMoment, + EContribContribution = 0, + EContribVariance, }; enum PGLVSPTypes { - EContribution = 0, - EVariance, + EVSPContribution = 0, + EVSPVariance, }; struct PGLImageSpaceGuidingBufferConfig { pgl_point2i resolution {0, 0}; bool contributionEstimate {true}; - PGLContributionTypes contributionType {PGLContributionTypes::EFirstMoment}; + PGLContributionTypes contributionType {PGLContributionTypes::EContribContribution}; //float maxContributionValue {FLT_MAX}; //TODO #if defined(OPENPGL_VSP_GUIDING) bool vspEstimate {false}; - PGLVSPTypes vspType {PGLVSPTypes::EContribution}; + PGLVSPTypes vspType {PGLVSPTypes::EVSPContribution}; #endif }; From 810f118f17622d4ce02a83b91a31bf958d3e6451 Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Tue, 19 Aug 2025 13:59:49 +0200 Subject: [PATCH 14/15] [doc] Updating the latest 0.8.0 changelog --- CHANGELOG.md | 87 ++++++++++++++++++++++++++++++++++++--- README.md | 90 +++++++++++++++++++++++++++++++++++------ doc/changelog_latest.md | 40 +++++++++++++++--- doc/compilation.md | 2 + 4 files changed, 195 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eba3799c..a71d6b55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,80 @@ # Version History +## Open PGL 0.8.0 + +- New (**Experimental**) Feature: + - Volume Scatter Probability Guiding (VSPG): + - This feature allows guiding the optimal volume scattering + probability (VSP) and is based on Xu et al. work “Volume Scatter + Probability Guiding”. This **experimental** feature can be enabled + by setting the CMake variable `OPENPGL_EF_VSP_GUIDING=ON`. The + volume scattering probability for a given direction can be queried + using the `VolumeScatterProbability` function of the + `SurfaceSamplingDistribution` and `VolumeSamplingDistribution` + classes. +- API changes: + - `SampleData`: + - New enum `ENextEventVolume` flag that identifies if the radiance + stored in this sample comes from a volume or surface scatting event + (e.g., if the next event is inside a volume or on a surface). +- API changes (`OPENPGL_EF_VSP_GUIDING=ON`): + - `FieldConfig`: + - `SetVarianceBasedVSP` when set to `true` the VSP value is + calculated based on the `variance` and not the `contribution` of + the nested volume and surface estimators. The default is `false` + (i.e., `contribution`). + - `VolumeScatterProbability` and `SurfaceSamplingDistribution`: + - `VolumeScatterProbability` this function returns the optimal VSP + probability for a given direction. Based on the type the VSP value + is either calculated based on the `contribution` or the `variance` + of the nested (surface and volume) estimators. +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON`): + - `ImageSpaceGuidingBuffer`: Moving to a config-based initialization + system and adding support to query the VSP for each pixel (i.e., + primary ray) of the image-space guiding buffer. The + `ImageSpaceGuidingBuffer` constructor now takes a + `ImageSpaceGuidingBuffer::Config` instead of a `Point2i` parameter. + + - The function to query the estimate of a pixel’s contribution got + renamed from `ContributionEstimate` to `GetContributionEstimate`. + + - `ImageSpaceGuidingBuffer::Config`: Class for setting up the + `ImageSpaceGuidingBuffer` (e.g., resolution, enabling contribution, + or VSP buffers). + + - The `Config` constructor initializes the config class. It takes a + `Point2i` defining the resolution of the desired + `ImageSpaceGuidingBuffer`. + - The resolution of the desired `ImageSpaceGuidingBuffer` can be + queried using `GetResolution`. + - Estimating the image contribution can be enabled or disables using + `EnableContributionEstimate`. + - If the estimation of the image contribution is enabled can be + checked using `ContributionEstimate`. + - The type of the estimated image contribution is defined via + `SetContributionType`. The type is defined via the + `PGLContributionTypes` enum and can be based on the contribution + (`EContribContribution`) or variance (`EContribVariance`). + - The type of the image contribution can be queried using + `GetContributionType`. +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON` and + `OPENPGL_EF_VSP_GUIDING=ON`): + - `ImageSpaceGuidingBuffer`: Adding the possibility to query the VSP + value. + - The VSP for a given pixel (i.e., primary ray) can be queried using + the `GetVolumeScatterProbabilityEstimate` function. + - `ImageSpaceGuidingBuffer::Config`: + - Estimating the image space VSP values can be activated and + deactivated using `EnableVolumeScatterProbabilityEstimate)`. + - If estimating of the image-space VSP values is enabled can be + checked using `VolumeScatterProbabilityEstimate`. + - The type of the estimated image-space VSP values is defined via + `SetVolumeScatterProbabilityType`. The type is defined via the + `PGLVSPTypes` enum and can be based on the contribution + (`EVSPContribution`) or variance (`EVSPVariance`). + - The type of the image-space VSP values can be queried using + `GetVolumeScatterProbabilityType`. + ## Open PGL 0.7.1 - Bugfixes: @@ -8,7 +83,7 @@ [\#23](https://github.com/RenderKit/openpgl/issues/23). - Fixing noisy stdout printouts [\#19](https://github.com/RenderKit/openpgl/issues/19). - - Improving robustness of the integer arithmetric used during the + - Improving robustness of the integer arithmetic used during the deterministic multi-threaded building of the spatial subdivision structure. - Improving numerical stability of fitting process of the VMM-based @@ -55,7 +130,7 @@ - `pgl_direction`: A new **wrapper** type for directional data. When using C++ `pgl_direction` can directly be assigned by and to `pgl_vec3f`. - - `pgl_spectrum`: A new **wrapper** type for spetral (i.e., linear + - `pgl_spectrum`: A new **wrapper** type for spectral (i.e., linear RGB) data. When using C++ `pgl_spectrum` can directly be assigned by and to `pgl_vec3f`. - `SampleData`: @@ -130,7 +205,7 @@ at progression `2^0`,`2^1`,…,`2^N`). - `IsReady`: If the ISGB is ready (i.e., at least one `Update` step was performed). - - `GetPixelContributionEstimate`: Returns the pixel contibution + - `GetPixelContributionEstimate`: Returns the pixel contribution estimate for a given pixel, which can be used, for example, for guided RR. - `Reset`: Resets the ISGB. @@ -141,7 +216,7 @@ - `albedo`: The albedo of the surface or the volume at the first scattering event (type `pgl_vec3f`). - `normal`: The normal at the first surface scattering event or the - ray dairection towards the camers if the first event is a volume + ray direction towards the cameras if the first event is a volume event (type `pgl_vec3f`). - `flags`: Bit encoded information about the sample (e.g., if the first scattering event is a volume event `Sample::EVolumeEvent`). @@ -150,7 +225,7 @@ - Compression for spectral and directional: To reduce the size of the `SampleData` and `ZeroValueSampleData` data types it is possible to - enable 32-Bit compression, which is mainly adviced when enabling the + enable 32-Bit compression, which is mainly advised when enabling the RC feature via `OPENPGL_EF_RADIANCE_CACHES=ON`. - `OPENPGL_DIRECTION_COMPRESSION`: Enables 32-Bit compression for `pgl_direction`. @@ -179,7 +254,7 @@ count this count is also used by `Open PGL`. - `SurfaceSamplingDistribution` and `VolumeSamplingDistribution`: - Added `GetId` function to return the unique id of the spatial - structure used to query the sampling distriubtion. + structure used to query the sampling distribution. - `Field` and `SampleStorage`, added `Compare` function to check if the data stored in different instances (e.g., generated by two separate runs) are similar (i.e., same spatial subdivisions and diff --git a/README.md b/README.md index 9f400ec7..c56b7a69 100644 --- a/README.md +++ b/README.md @@ -50,19 +50,80 @@ specification is still in flux and might change with upcoming releases. The full version history can be found [here](./CHANGELOG.md) -## Open PGL 0.7.1 - -- Bugfixes: - - Fixing invalidation of the guiding field on initial creation if a - cell contains no samples - [\#23](https://github.com/RenderKit/openpgl/issues/23). - - Fixing noisy stdout printouts - [\#19](https://github.com/RenderKit/openpgl/issues/19). - - Improving robustness of the integer arithmetric used during the - deterministic multi-threaded building of the spatial subdivision - structure. - - Improving numerical stability of fitting process of the VMM-based - guiding models. +## Open PGL 0.8.0 + +- New (**Experimental**) Feature: + - Volume Scatter Probability Guiding (VSPG): + - This feature allows guiding the optimal volume scattering + probability (VSP) and is based on Xu et al. work “Volume Scatter + Probability Guiding”. This **experimental** feature can be enabled + by setting the CMake variable `OPENPGL_EF_VSP_GUIDING=ON`. The + volume scattering probability for a given direction can be queried + using the `VolumeScatterProbability` function of the + `SurfaceSamplingDistribution` and `VolumeSamplingDistribution` + classes. +- API changes: + - `SampleData`: + - New enum `ENextEventVolume` flag that identifies if the radiance + stored in this sample comes from a volume or surface scatting event + (e.g., if the next event is inside a volume or on a surface). +- API changes (`OPENPGL_EF_VSP_GUIDING=ON`): + - `FieldConfig`: + - `SetVarianceBasedVSP` when set to `true` the VSP value is + calculated based on the `variance` and not the `contribution` of + the nested volume and surface estimators. The default is `false` + (i.e., `contribution`). + - `VolumeScatterProbability` and `SurfaceSamplingDistribution`: + - `VolumeScatterProbability` this function returns the optimal VSP + probability for a given direction. Based on the type the VSP value + is either calculated based on the `contribution` or the `variance` + of the nested (surface and volume) estimators. +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON`): + - `ImageSpaceGuidingBuffer`: Moving to a config-based initialization + system and adding support to query the VSP for each pixel (i.e., + primary ray) of the image-space guiding buffer. The + `ImageSpaceGuidingBuffer` constructor now takes a + `ImageSpaceGuidingBuffer::Config` instead of a `Point2i` parameter. + + - The function to query the estimate of a pixel’s contribution got + renamed from `ContributionEstimate` to `GetContributionEstimate`. + + - `ImageSpaceGuidingBuffer::Config`: Class for setting up the + `ImageSpaceGuidingBuffer` (e.g., resolution, enabling contribution, + or VSP buffers). + + - The `Config` constructor initializes the config class. It takes a + `Point2i` defining the resolution of the desired + `ImageSpaceGuidingBuffer`. + - The resolution of the desired `ImageSpaceGuidingBuffer` can be + queried using `GetResolution`. + - Estimating the image contribution can be enabled or disables using + `EnableContributionEstimate`. + - If the estimation of the image contribution is enabled can be + checked using `ContributionEstimate`. + - The type of the estimated image contribution is defined via + `SetContributionType`. The type is defined via the + `PGLContributionTypes` enum and can be based on the contribution + (`EContribContribution`) or variance (`EContribVariance`). + - The type of the image contribution can be queried using + `GetContributionType`. +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON` and + `OPENPGL_EF_VSP_GUIDING=ON`): + - `ImageSpaceGuidingBuffer`: Adding the possibility to query the VSP + value. + - The VSP for a given pixel (i.e., primary ray) can be queried using + the `GetVolumeScatterProbabilityEstimate` function. + - `ImageSpaceGuidingBuffer::Config`: + - Estimating the image space VSP values can be activated and + deactivated using `EnableVolumeScatterProbabilityEstimate)`. + - If estimating of the image-space VSP values is enabled can be + checked using `VolumeScatterProbabilityEstimate`. + - The type of the estimated image-space VSP values is defined via + `SetVolumeScatterProbabilityType`. The type is defined via the + `PGLVSPTypes` enum and can be based on the contribution + (`EVSPContribution`) or variance (`EVSPVariance`). + - The type of the image-space VSP values can be queried using + `GetVolumeScatterProbabilityType`. # Support and Contact @@ -206,6 +267,9 @@ Configure the Open PGL build using: - `OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER`: Enables the **experimental** image-space guiding buffer feature (default `OFF`). + - `OPENPGL_EF_VSP_GUIDING`: Enables the **experimental** volume + scatter probability guiding feature (default `OFF`). + - `OPENPGL_DIRECTION_COMPRESSION`: Enables the 32Bit compression for directional data stored in `pgl_direction` (default `OFF`). diff --git a/doc/changelog_latest.md b/doc/changelog_latest.md index 375af45c..94b12510 100644 --- a/doc/changelog_latest.md +++ b/doc/changelog_latest.md @@ -1,7 +1,37 @@ ## Open PGL 0.8.0 -- Bugfixes: - - Fixing invalidation of the guiding field on initial creation if a cell contains no samples [#23](https://github.com/RenderKit/openpgl/issues/23). - - Fixing noisy stdout printouts [#19](https://github.com/RenderKit/openpgl/issues/19). - - Improving robustness of the integer arithmetric used during the deterministic multi-threaded building of the spatial subdivision structure. - - Improving numerical stability of fitting process of the VMM-based guiding models. +- New (**Experimental**) Feature: + - Volume Scatter Probability Guiding (VSPG): + - This feature allows guiding the optimal volume scattering probability (VSP) and is based on Xu et al. work "Volume Scatter Probability Guiding". + This **experimental** feature can be enabled by setting the CMake variable `OPENPGL_EF_VSP_GUIDING=ON`. + The volume scattering probability for a given direction can be queried using the `VolumeScatterProbability` function of the `SurfaceSamplingDistribution` and `VolumeSamplingDistribution` classes. +- API changes: + - `SampleData`: + - New enum `ENextEventVolume` flag that identifies if the radiance stored in this sample comes from a volume or surface scatting event (e.g., if the next event is inside a volume or on a surface). +- API changes (`OPENPGL_EF_VSP_GUIDING=ON`): + - `FieldConfig`: + - `SetVarianceBasedVSP` when set to `true` the VSP value is calculated based on the `variance` and not the `contribution` of the nested volume and surface estimators. The default is `false` (i.e., `contribution`). + - `VolumeScatterProbability` and `SurfaceSamplingDistribution`: + - `VolumeScatterProbability` this function returns the optimal VSP probability for a given direction. Based on the type the VSP value is either calculated based on the `contribution` or the `variance` of the nested (surface and volume) estimators. +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON`): + - `ImageSpaceGuidingBuffer`: + Moving to a config-based initialization system and adding support to query the VSP for each pixel (i.e., primary ray) of the image-space guiding buffer. + The `ImageSpaceGuidingBuffer` constructor now takes a `ImageSpaceGuidingBuffer::Config` instead of a `Point2i` parameter. + - The function to query the estimate of a pixel's contribution got renamed from `ContributionEstimate` to `GetContributionEstimate`. + + - `ImageSpaceGuidingBuffer::Config`: Class for setting up the `ImageSpaceGuidingBuffer` (e.g., resolution, enabling contribution, or VSP buffers). + - The `Config` constructor initializes the config class. It takes a `Point2i` defining the resolution of the desired `ImageSpaceGuidingBuffer`. + - The resolution of the desired `ImageSpaceGuidingBuffer` can be queried using `GetResolution`. + - Estimating the image contribution can be enabled or disables using `EnableContributionEstimate`. + - If the estimation of the image contribution is enabled can be checked using `ContributionEstimate`. + - The type of the estimated image contribution is defined via `SetContributionType`. The type is defined via the `PGLContributionTypes` enum and can be based on the contribution (`EContribContribution`) or variance (`EContribVariance`). + - The type of the image contribution can be queried using `GetContributionType`. + +- API changes (`OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER=ON` and `OPENPGL_EF_VSP_GUIDING=ON`): + - `ImageSpaceGuidingBuffer`: Adding the possibility to query the VSP value. + - The VSP for a given pixel (i.e., primary ray) can be queried using the `GetVolumeScatterProbabilityEstimate` function. + - `ImageSpaceGuidingBuffer::Config`: + - Estimating the image space VSP values can be activated and deactivated using `EnableVolumeScatterProbabilityEstimate)`. + - If estimating of the image-space VSP values is enabled can be checked using `VolumeScatterProbabilityEstimate`. + - The type of the estimated image-space VSP values is defined via `SetVolumeScatterProbabilityType`. The type is defined via the `PGLVSPTypes` enum and can be based on the contribution (`EVSPContribution`) or variance (`EVSPVariance`). + - The type of the image-space VSP values can be queried using `GetVolumeScatterProbabilityType`. \ No newline at end of file diff --git a/doc/compilation.md b/doc/compilation.md index bd3ca6f9..59cf2945 100644 --- a/doc/compilation.md +++ b/doc/compilation.md @@ -101,6 +101,8 @@ Configure the Open PGL build using: - `OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER`: Enables the **experimental** image-space guiding buffer feature (default `OFF`). + - `OPENPGL_EF_VSP_GUIDING`: Enables the **experimental** volume scatter probability guiding feature (default `OFF`). + - `OPENPGL_DIRECTION_COMPRESSION`: Enables the 32Bit compression for directional data stored in `pgl_direction` (default `OFF`). - `OPENPGL_RADIANCE_COMPRESSION`: Enables the 32Bit compression for RGB data stored in `pgl_spectrum` (default `OFF`). From 8e20394b07a5ecd83fb4f41f310f32057b75a29c Mon Sep 17 00:00:00 2001 From: Sebastian Herholz Date: Tue, 19 Aug 2025 14:00:40 +0200 Subject: [PATCH 15/15] [cmake] Revert to the default settings. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1341ba..f7062441 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,9 +51,9 @@ option(OPENPGL_BUILD_CHECK_TOOL "Build check tool application." OFF) try_compile(COMPILER_SUPPORTS_ARM_NEON "${CMAKE_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/cmake/check_arm_neon.cpp") -OPTION(OPENPGL_EF_RADIANCE_CACHES "Enables experimental feature (ir)radiance caches." ON) -OPTION(OPENPGL_EF_VSP_GUIDING "Enables experimental feature volume scatter probability guiding." ON) -OPTION(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER "Enables experimental feature ImageSpaceGuidignBuffer." ON) +OPTION(OPENPGL_EF_RADIANCE_CACHES "Enables experimental feature (ir)radiance caches." OFF) +OPTION(OPENPGL_EF_VSP_GUIDING "Enables experimental feature volume scatter probability guiding." OFF) +OPTION(OPENPGL_EF_IMAGE_SPACE_GUIDING_BUFFER "Enables experimental feature ImageSpaceGuidignBuffer." OFF) OPTION(OPENPGL_DIRECTION_COMPRESSION "Using 32-Bit compression to represent directions." OFF) OPTION(OPENPGL_RADIANCE_COMPRESSION "Using RGBE 32-Bit compression to represent radiance data (linear RGB)." OFF)