Improvements to CMGEN handling of cubemaps

- cmgen now creates reflections maps for all input
assets by default instead of just for equirectangular 
images.

- equirectangular decode doesn't mirror -- that's
done by the mirroring code now.

- mirroring can be turned of with --no-mirror

- option --mirror is gone

- faster mirroring code (do it before generating
  mipmaps)

- added labels to faces of debug.png environment

- added a debug equirectangular image in third_party
(creative commons license)
This commit is contained in:
Pixelflinger
2018-09-21 00:30:26 -07:00
committed by Mathias Agopian
parent 1396cc751c
commit 09830cd126
5 changed files with 28 additions and 32 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 232 KiB

View File

@@ -1 +1,2 @@
https://hdrihaven.com/
https://mapswire.com/world/physical-maps/

BIN
third_party/environments/earth.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View File

@@ -51,14 +51,14 @@ void CubemapUtils::equirectangularToCubemap(Cubemap& dst, const Image& src) {
[&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) {
for (size_t x=0 ; x<dim ; ++x, ++data) {
// calculate how many samples we need based on dx, dy in the source
// x = cos(phi) sin(theta)
// y = -sin(phi)
// z = -cos(phi) cos(theta)
// x = cos(phi) sin(theta)
// y = sin(phi)
// z = cos(phi) cos(theta)
const double3 s0(dst.getDirectionFor(f, x, y));
const double t0 = std::atan2(s0.x, -s0.z);
const double t0 = std::atan2(s0.x, s0.z);
const double p0 = std::asin(s0.y);
const double3 s1(dst.getDirectionFor(f, x+1, y+1));
const double t1 = std::atan2(s1.x, -s1.z);
const double t1 = std::atan2(s1.x, s1.z);
const double p1 = std::asin(s1.y);
const double dt = std::abs(t1 - t0);
const double dp = std::abs(p1 - p0);
@@ -72,10 +72,10 @@ void CubemapUtils::equirectangularToCubemap(Cubemap& dst, const Image& src) {
// Generate numSamples in our destination pixels and map them to input pixels
const double2 h = hammersley(uint32_t(sample), iNumSamples);
const double3 s(dst.getDirectionFor(f, x + h.x, y + h.y));
float xf = float(std::atan2(s.x, -s.z) * M_1_PI); // range [-1.0, 1.0]
float yf = float(std::asin(-s.y) * (2 * M_1_PI)); // range [-1.0, 1.0]
float xf = float(std::atan2(s.x, s.z) * M_1_PI); // range [-1.0, 1.0]
float yf = float(std::asin(s.y) * (2 * M_1_PI)); // range [-1.0, 1.0]
xf = (xf + 1) * 0.5f * (width -1); // range [0, width [
yf = (yf + 1) * 0.5f * (height-1); // range [0, height[
yf = (1 - yf) * 0.5f * (height-1); // range [0, height[
// we can't use filterAt() here because it reads past the width/height
// which is okay for cubmaps but not for square images
c += Cubemap::sampleAt(src.getPixelRef((uint32_t)xf, (uint32_t)yf));

View File

@@ -149,8 +149,8 @@ static void printUsage(char* name) {
" Extract faces of the cubemap into <dir>\n\n"
" --extract-blur=roughness\n"
" Blurs the cubemap before saving the faces using the roughness blur\n\n"
" --mirror\n"
" Mirrors generated cubemaps for reflections\n\n"
" --no-mirror\n"
" Skip mirroring of generated cubemaps (for assets with mirroring already backed in)\n\n"
" --ibl-samples=numSamples\n"
" Number of samples to use for IBL integrations (default 1024)\n\n"
"\n"
@@ -211,7 +211,7 @@ static int handleCommandLineArgments(int argc, char* argv[]) {
{ "ibl-dfg-multiscatter", no_argument, nullptr, 'u' },
{ "ibl-samples", required_argument, nullptr, 'k' },
{ "deploy", required_argument, nullptr, 'x' },
{ "mirror", no_argument, nullptr, 'm' },
{ "no-mirror", no_argument, nullptr, 'm' },
{ "debug", no_argument, nullptr, 'd' },
{ nullptr, 0, 0, 0 } // termination of the option list
};
@@ -449,7 +449,6 @@ int main(int argc, char* argv[]) {
Image temp;
Cubemap cml = CubemapUtils::create(temp, dim, isHorizontal);
CubemapUtils::copyImage(temp, inputImage);
cml.makeSeamless();
images.push_back(std::move(temp));
levels.push_back(std::move(cml));
} else if (width == 2 * height) {
@@ -461,7 +460,6 @@ int main(int argc, char* argv[]) {
Image temp;
Cubemap cml = CubemapUtils::create(temp, dim);
CubemapUtils::equirectangularToCubemap(cml, inputImage);
cml.makeSeamless();
images.push_back(std::move(temp));
levels.push_back(std::move(cml));
} else {
@@ -492,36 +490,33 @@ int main(int argc, char* argv[]) {
CubemapUtils::generateUVGrid(cml, 1);
}
cml.makeSeamless();
images.push_back(std::move(temp));
levels.push_back(std::move(cml));
}
// Now generate all the mipmap levels
generateMipmaps(levels, images);
// we mirror by default -- the mirror option in fact un-mirrors.
g_mirror = !g_mirror;
if (g_mirror) {
if (!g_quiet) {
std::cout << "Mirroring..." << std::endl;
}
std::vector<Cubemap> mirrorLevels;
std::vector<Image> mirrorImages;
for (auto& level : levels) {
Image temp;
Cubemap cml = CubemapUtils::create(temp, level.getDimensions());
CubemapUtils::mirrorCubemap(cml, level);
cml.makeSeamless();
mirrorImages.push_back(std::move(temp));
mirrorLevels.push_back(std::move(cml));
Image temp;
Cubemap cml = CubemapUtils::create(temp, levels[0].getDimensions());
CubemapUtils::mirrorCubemap(cml, levels[0]);
std::swap(levels[0], cml);
std::swap(images[0], temp);
} else {
if (!g_quiet) {
std::cout << "Skipped mirroring." << std::endl;
}
std::swap(levels, mirrorLevels);
std::swap(images, mirrorImages);
}
// make the cubemap seamless
levels[0].makeSeamless();
// Now generate all the mipmap levels
generateMipmaps(levels, images);
if (g_sh_compute) {
if (!g_quiet) {
std::cout << "Spherical harmonics..." << std::endl;