From 741b1a412dcbc31f2b2cb302dcff641110a2e2c8 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 28 Sep 2018 17:08:48 -0700 Subject: [PATCH] experimental: add octahedron output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Octahedron output support for cmgen. use —type=octahedron. This is still fairly experimental. --- tools/cmgen/src/CubemapUtils.cpp | 37 ++++++++++++++++++++++++++++++++ tools/cmgen/src/CubemapUtils.h | 2 ++ tools/cmgen/src/cmgen.cpp | 37 ++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/tools/cmgen/src/CubemapUtils.cpp b/tools/cmgen/src/CubemapUtils.cpp index 7a7d6dfd2a..3f895821a6 100644 --- a/tools/cmgen/src/CubemapUtils.cpp +++ b/tools/cmgen/src/CubemapUtils.cpp @@ -21,6 +21,7 @@ #include #include +#include #include @@ -138,6 +139,42 @@ void CubemapUtils::cubemapToEquirectangular(Image& dst, const Cubemap& src) { js.reset(); } +void CubemapUtils::cubemapToOctahedron(Image& dst, const Cubemap& src) { + const double w = dst.getWidth(); + const double h = dst.getHeight(); + auto parallelJobTask = [&](size_t j0, size_t count) { + for (size_t j = j0; j < j0 + count; j++) { + for (size_t i = 0; i < w; i++) { + float3 c = 0; + const size_t numSamples = 64; // TODO: how to chose numsamples + for (size_t sample = 0; sample < numSamples; sample++) { + const double2 u = hammersley(uint32_t(sample), 1.0f / numSamples); + double x = 2.0 * (i + u.x) / w - 1.0; + double z = 2.0 * (j + u.y) / h - 1.0; + double y; + if (std::abs(z) > (1.0 - std::abs(x))) { + double u = x < 0 ? std::abs(z) - 1 : 1 - std::abs(z); + double v = z < 0 ? std::abs(x) - 1 : 1 - std::abs(x); + x = u; + z = v; + y = (std::abs(x) + std::abs(z)) - 1.0; + } else { + y = 1.0 - (std::abs(x) + std::abs(z)); + } + c += src.filterAt({x, y, z}); + } + Cubemap::writeAt(dst.getPixelRef(i, j), c * (1.0 / numSamples)); + } + } + }; + + JobSystem& js = getJobSystem(); + auto job = jobs::parallel_for(js, nullptr, 0, uint32_t(h), + std::ref(parallelJobTask), jobs::CountSplitter<1, 8>()); + js.runAndWait(job); + js.reset(); +} + void CubemapUtils::crossToCubemap(Cubemap& dst, const Image& src) { process(dst, [&](EmptyState&, size_t iy, Cubemap::Face f, Cubemap::Texel* data, size_t dimension) { diff --git a/tools/cmgen/src/CubemapUtils.h b/tools/cmgen/src/CubemapUtils.h index b8a3fc2e23..74c8c2a300 100644 --- a/tools/cmgen/src/CubemapUtils.h +++ b/tools/cmgen/src/CubemapUtils.h @@ -51,6 +51,8 @@ public: static void cubemapToEquirectangular(Image& dst, const Cubemap& src); + static void cubemapToOctahedron(Image& dst, const Cubemap& src); + // Convert h or v cross Image to a Cubemap static void crossToCubemap(Cubemap& dst, const Image& src); diff --git a/tools/cmgen/src/cmgen.cpp b/tools/cmgen/src/cmgen.cpp index f2687d171b..18953576e5 100644 --- a/tools/cmgen/src/cmgen.cpp +++ b/tools/cmgen/src/cmgen.cpp @@ -51,7 +51,7 @@ static const size_t DFG_LUT_DEFAULT_SIZE = 128; static const size_t IBL_DEFAULT_SIZE = 256; enum class OutputType { - FACES, KTX, EQUIRECT + FACES, KTX, EQUIRECT, OCTAHEDRON }; static image::ImageEncoder::Format g_format = image::ImageEncoder::Format::PNG; @@ -140,7 +140,7 @@ static void printUsage(char* name) { " Print copyright and license information\n\n" " --quiet, -q\n" " Quiet mode. Suppress all non-error output\n\n" - " --type=[faces|equirect|ktx], -t [cubemap|equirect|ktx]\n" + " --type=[faces|equirect|octahedron|ktx], -t [cubemap|equirect|octahedron|ktx]\n" " Specify output type (default: cubemap)\n\n" " --format=[exr|hdr|psd|rgbm|png|dds|ktx], -f [exr|hdr|psd|rgbm|png|dds|ktx]\n" " Specify output file format. ktx implies -type=ktx.\n\n" @@ -261,6 +261,10 @@ static int handleCommandLineArgments(int argc, char* argv[]) { g_type = OutputType::EQUIRECT; type_specified = true; } + if (arg == "octahedron") { + g_type = OutputType::OCTAHEDRON; + type_specified = true; + } break; case 'f': if (arg == "png") { @@ -758,6 +762,16 @@ void iblMipmapPrefilter(const utils::Path& iname, continue; } + if (g_type == OutputType::OCTAHEDRON) { + size_t dim = dst.getDimensions(); + std::unique_ptr buf(new uint8_t[dim * dim * sizeof(float3)]); + Image image(std::move(buf), dim, dim, dim * sizeof(float3), sizeof(float3)); + CubemapUtils::cubemapToOctahedron(image, dst); + std::string filename = outputDir + ("is_m" + std::to_string(level) + ext); + saveImage(filename, g_format, image, g_compression); + continue; + } + for (size_t i = 0; i < 6; i++) { Cubemap::Face face = (Cubemap::Face)i; std::string filename = outputDir @@ -850,6 +864,15 @@ void iblRoughnessPrefilter(const utils::Path& iname, continue; } + if (g_type == OutputType::OCTAHEDRON) { + std::unique_ptr buf(new uint8_t[dim * dim * sizeof(float3)]); + Image image(std::move(buf), dim, dim, dim * sizeof(float3), sizeof(float3)); + CubemapUtils::cubemapToOctahedron(image, dst); + std::string filename = outputDir + ("m" + std::to_string(level) + ext); + saveImage(filename, g_format, image, g_compression); + continue; + } + for (size_t j = 0; j < 6; j++) { Cubemap::Face face = (Cubemap::Face) j; std::string filename = outputDir @@ -1017,6 +1040,16 @@ void extractCubemapFaces(const utils::Path& iname, const Cubemap& cm, const util return; } + if (g_type == OutputType::OCTAHEDRON) { + size_t dim = cm.getDimensions(); + std::unique_ptr buf(new uint8_t[dim * dim * sizeof(float3)]); + Image image(std::move(buf), dim, dim, dim * sizeof(float3), sizeof(float3)); + CubemapUtils::cubemapToOctahedron(image, cm); + std::string filename = outputDir + ("skybox" + ext); + saveImage(filename, g_format, image, g_compression); + return; + } + for (size_t i = 0; i < 6; i++) { Cubemap::Face face = (Cubemap::Face) i; std::string filename(outputDir + (CubemapUtils::getFaceName(face) + ext));