Improve low roughness significantly

Filament will now allow incomplete mipmap chains for the IBL and
map the roughness to the available chain.

This allows to create roughness cubemaps with a minim size for
roughness==1, instead of always mapping it to 1x1.

cmgen will now use 16x16 cubemaps for roughness==1, which
improves the quality of rough objects significantly.

The beauty of this is that there is no asset or API change. Old assets
will continue to work like before.
This commit is contained in:
Mathias Agopian
2019-12-06 17:21:15 -08:00
committed by Mathias Agopian
parent 2c1454270e
commit dbda77b091
3 changed files with 22 additions and 9 deletions

View File

@@ -5,6 +5,8 @@ A new header is inserted each time a *tag* is created.
## Next release
- Improve high roughness material rendering by default when regenerating environments maps
## v1.4.3
- Fixed an assertion when a parameter array occurs last in a material definition.

View File

@@ -156,12 +156,6 @@ IndirectLight* IndirectLight::Builder::build(Engine& engine) {
return nullptr;
}
if (!ASSERT_POSTCONDITION_NON_FATAL(mImpl->mReflectionsMap->getLevels() ==
upcast(mImpl->mReflectionsMap)->getMaxLevelCount(),
"reflection map must have %u mipmap levels",
upcast(mImpl->mReflectionsMap)->getMaxLevelCount())) {
return nullptr;
}
if (IBL_INTEGRATION == IBL_INTEGRATION_IMPORTANCE_SAMPLING) {
mImpl->mReflectionsMap->generateMipmaps(engine);
}

View File

@@ -58,6 +58,7 @@ enum class ShFile {
static const size_t DFG_LUT_DEFAULT_SIZE = 128;
static const size_t IBL_DEFAULT_SIZE = 256;
static const size_t IBL_DEFAULT_MIN_LOD_SIZE = 16;
enum class OutputType {
FACES, KTX, EQUIRECT, OCTAHEDRON
@@ -71,6 +72,7 @@ static float g_extract_blur = 0.0;
static utils::Path g_extract_dir;
static size_t g_output_size = 0;
static size_t g_min_lod_size = 0;
static bool g_quiet = false;
static bool g_debug = false;
@@ -210,6 +212,8 @@ static void printUsage(char* name) {
" Diffuse irradiance into <dir>\n\n"
" --ibl-no-prefilter\n"
" Use importance sampling instead of prefiltered importance sampling\n\n"
" --ibl-min-lod-size\n"
" Minimum LOD size [default: 16]\n\n"
" --sh=bands\n"
" SH decomposition of input cubemap\n\n"
" --sh-output=filename.[exr|hdr|psd|rgbm|rgb32f|png|dds|txt]\n"
@@ -240,7 +244,7 @@ static void license() {
}
static int handleCommandLineArgments(int argc, char* argv[]) {
static constexpr const char* OPTSTR = "hqidt:f:c:s:x:w:";
static constexpr const char* OPTSTR = "hqidt:f:c:s:x:w:S:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "license", no_argument, nullptr, 'l' },
@@ -264,6 +268,7 @@ static int handleCommandLineArgments(int argc, char* argv[]) {
{ "ibl-dfg-multiscatter", no_argument, nullptr, 'u' },
{ "ibl-dfg-cloth", no_argument, nullptr, 'C' },
{ "ibl-no-prefilter", no_argument, nullptr, 'n' },
{ "ibl-min-lod-size", required_argument, nullptr, 'S' },
{ "ibl-samples", required_argument, nullptr, 'k' },
{ "deploy", required_argument, nullptr, 'x' },
{ "no-mirror", no_argument, nullptr, 'm' },
@@ -353,6 +358,13 @@ static int handleCommandLineArgments(int argc, char* argv[]) {
exit(0);
}
break;
case 'S':
g_min_lod_size = std::stoul(arg);
if (!isPOT(g_min_lod_size)) {
std::cerr << "min LOD size must be a power of two" << std::endl;
exit(0);
}
break;
case 'z':
g_sh_compute = 1;
g_sh_output = true;
@@ -877,8 +889,13 @@ void iblRoughnessPrefilter(
const bool DEBUG_FULL_RESOLUTION = false;
const size_t baseExp = utils::ctz(g_output_size ? g_output_size : IBL_DEFAULT_SIZE);
size_t minLod = utils::ctz(g_min_lod_size ? g_min_lod_size : IBL_DEFAULT_MIN_LOD_SIZE);
if (minLod >= baseExp) {
minLod = 0;
}
size_t numSamples = g_num_samples;
const size_t numLevels = baseExp + 1;
const size_t numLevels = (baseExp + 1) - minLod;
// It's convenient to create an empty KTX bundle on the stack in this scope, regardless of
// whether KTX is requested. It does not consume memory if empty.
@@ -895,7 +912,7 @@ void iblRoughnessPrefilter(
.pixelDepth = 0,
};
for (ssize_t i = baseExp; i >= 0; --i) {
for (ssize_t i = baseExp; i >= ssize_t((baseExp + 1) - numLevels) ; --i) {
const size_t dim = 1U << (DEBUG_FULL_RESOLUTION ? baseExp : i); // NOLINT
const size_t level = baseExp - i;
if (level >= 2) {