diff --git a/libs/ibl/include/ibl/Cubemap.h b/libs/ibl/include/ibl/Cubemap.h index 2e49ff9ec9..192abc5eb8 100644 --- a/libs/ibl/include/ibl/Cubemap.h +++ b/libs/ibl/include/ibl/Cubemap.h @@ -99,7 +99,8 @@ public: inline Texel filterAt(const filament::math::double3& direction) const; //! samples an image at the given location in pixel using bilinear filtering - static Texel filterAt(const Image& image, double x, double y); + static Texel filterAt(const Image& image, float x, float y); + static Texel filterAtCenter(const Image& image, size_t x, size_t y); //! samples two cubemaps in a given direction and lerps the result by a given lerp factor static Texel trilinearFilterAt(const Cubemap& c0, const Cubemap& c1, double lerp, diff --git a/libs/ibl/include/ibl/CubemapUtils.h b/libs/ibl/include/ibl/CubemapUtils.h index 8ef9e696a0..84dac6aa01 100644 --- a/libs/ibl/include/ibl/CubemapUtils.h +++ b/libs/ibl/include/ibl/CubemapUtils.h @@ -55,6 +55,14 @@ public: ReduceProc reduce = [](STATE&) {}, const STATE& prototype = STATE()); + //! process the cubemap + template + static void processSingleThreaded(Cubemap& cm, + utils::JobSystem& js, + ScanlineProc proc, + ReduceProc reduce = [](STATE&) {}, + const STATE& prototype = STATE()); + //! Converts equirectangular Image to a Cubemap static void equirectangularToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src); diff --git a/libs/ibl/src/Cubemap.cpp b/libs/ibl/src/Cubemap.cpp index 329efb7151..f5413ab192 100644 --- a/libs/ibl/src/Cubemap.cpp +++ b/libs/ibl/src/Cubemap.cpp @@ -169,7 +169,7 @@ void Cubemap::makeSeamless() { corners(Face::NY); } -Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) { +Cubemap::Texel Cubemap::filterAt(const Image& image, float x, float y) { const size_t x0 = size_t(x); const size_t y0 = size_t(y); // we allow ourselves to read past the width/height of the Image because the data is valid @@ -188,6 +188,18 @@ Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) { return (one_minus_u*one_minus_v)*c0 + (u*one_minus_v)*c1 + (one_minus_u*v)*c2 + (u*v)*c3; } +Cubemap::Texel Cubemap::filterAtCenter(const Image& image, size_t x0, size_t y0) { + // we allow ourselves to read past the width/height of the Image because the data is valid + // and contain the "seamless" data. + size_t x1 = x0 + 1; + size_t y1 = y0 + 1; + const Texel& c0 = sampleAt(image.getPixelRef(x0, y0)); + const Texel& c1 = sampleAt(image.getPixelRef(x1, y0)); + const Texel& c2 = sampleAt(image.getPixelRef(x0, y1)); + const Texel& c3 = sampleAt(image.getPixelRef(x1, y1)); + return (c0 + c1 + c2 + c3) * 0.25f; +} + Cubemap::Texel Cubemap::trilinearFilterAt(const Cubemap& l0, const Cubemap& l1, double lerp, const double3& L) { diff --git a/libs/ibl/src/CubemapUtils.cpp b/libs/ibl/src/CubemapUtils.cpp index 6955364288..4505546cbb 100644 --- a/libs/ibl/src/CubemapUtils.cpp +++ b/libs/ibl/src/CubemapUtils.cpp @@ -229,13 +229,13 @@ void CubemapUtils::crossToCubemap(JobSystem& js, Cubemap& dst, const Image& src) void CubemapUtils::downsampleCubemapLevelBoxFilter(JobSystem& js, Cubemap& dst, const Cubemap& src) { size_t scale = src.getDimensions() / dst.getDimensions(); - process(dst, js, + processSingleThreaded(dst, js, [&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) { - const Image& image(src.getImageForFace(f)); - for (size_t x=0 ; x(dst, js, + processSingleThreaded(dst, js, [&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) { for (size_t x=0 ; x(image.getPixelRef(0, y)); + proc(s, y, f, data, dim); + } + } + reduce(s); + return; + } + + STATE states[6]; for (STATE& s : states) { s = prototype; @@ -60,7 +76,7 @@ void CubemapUtils::process( if (std::is_same::value) { auto job = jobs::parallel_for(js, parent, 0, uint32_t(dim), - std::ref(parallelJobTask), jobs::CountSplitter<1, 8>()); + std::ref(parallelJobTask), jobs::CountSplitter<64, 8>()); // we need to wait here because parallelJobTask is passed by reference js.runAndWait(job); @@ -79,6 +95,30 @@ void CubemapUtils::process( } } +template +void CubemapUtils::processSingleThreaded( + Cubemap& cm, + utils::JobSystem& js, + CubemapUtils::ScanlineProc proc, + ReduceProc reduce, + const STATE& prototype) { + using namespace utils; + + const size_t dim = cm.getDimensions(); + + STATE s; + for (size_t faceIndex = 0; faceIndex < 6; faceIndex++) { + const Cubemap::Face f = (Cubemap::Face)faceIndex; + Image& image(cm.getImageForFace(f)); + for (size_t y = 0; y < dim; y++) { + Cubemap::Texel* data = static_cast(image.getPixelRef(0, y)); + proc(s, y, f, data, dim); + } + } + reduce(s); +} + + } // namespace ibl } // namespace filament