diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 1de1d7fa78..b07a4de609 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -393,7 +393,10 @@ public class View { /** * List of available tone-mapping operators + * + * @deprecated Use ColorGrading instead */ + @Deprecated public enum ToneMapping { /** * Equivalent to disabling tone-mapping. @@ -725,7 +728,10 @@ public class View { * Enables or disables tone-mapping in the post-processing stage. Enabled by default. * * @param type Tone-mapping function. + * + * @deprecated Use {@link #setColorGrading(com.google.android.filament.ColorGrading)} */ + @Deprecated public void setToneMapping(@NonNull ToneMapping type) { nSetToneMapping(getNativeObject(), type.ordinal()); } @@ -733,7 +739,10 @@ public class View { /** * Returns the tone-mapping function. * @return tone-mapping function. + * + * @deprecated Use {@link #getColorGrading()} */ + @Deprecated @NonNull public ToneMapping getToneMapping() { return ToneMapping.values()[nGetToneMapping(getNativeObject())]; diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 3d8e82e311..78ae52ed3d 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -14,6 +14,7 @@ set(PUBLIC_HDRS include/filament/Box.h include/filament/Camera.h include/filament/Color.h + include/filament/ColorGrading.h include/filament/DebugRegistry.h include/filament/Engine.h include/filament/Exposure.h @@ -55,6 +56,7 @@ set(SRCS src/Box.cpp src/Camera.cpp src/Color.cpp + src/ColorGrading.cpp src/Culler.cpp src/DebugRegistry.cpp src/DFG.cpp @@ -84,7 +86,6 @@ set(SRCS src/SwapChain.cpp src/Stream.cpp src/Texture.cpp - src/Tonemapper.cpp src/UniformBuffer.cpp src/View.cpp src/Viewport.cpp @@ -108,6 +109,7 @@ set(PRIVATE_HDRS src/fg/fg/VirtualResource.h src/details/Allocators.h src/details/Camera.h + src/details/ColorGrading.h src/details/Culler.h src/details/DebugRegistry.h src/details/DFG.h @@ -130,10 +132,8 @@ set(PRIVATE_HDRS src/details/Stream.h src/details/SwapChain.h src/details/Texture.h - src/details/Tonemapper.h src/details/VertexBuffer.h src/details/View.h - src/ACES.h src/FilamentAPI-impl.h src/FrameInfo.h src/GPUBuffer.h @@ -141,6 +141,7 @@ set(PRIVATE_HDRS src/MaterialParser.h src/PostProcessManager.h src/RenderPass.h + src/ToneMapping.h src/UniformBuffer.h src/upcast.h) diff --git a/filament/include/filament/ColorGrading.h b/filament/include/filament/ColorGrading.h new file mode 100644 index 0000000000..8679f748e8 --- /dev/null +++ b/filament/include/filament/ColorGrading.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! \file + +#ifndef TNT_FILAMENT_COLOR_GRADING_H +#define TNT_FILAMENT_COLOR_GRADING_H + +#include + +#include + +#include + +namespace filament { + +class Engine; +class FColorGrading; + +class UTILS_PUBLIC ColorGrading : public FilamentAPI { + struct BuilderDetails; +public: + enum class ToneMapping : uint8_t { + LINEAR = 0, //!< Linear tone mapping (i.e. no tone mapping) + ACES = 1, //!< ACES tone mapping (ODT+RRT in ) + FILMIC = 2, //!< Filmic tone mapping, modelled after ACES but applied in sRGB space + REINHARD = 3, //!< Reinhard luma-based tone mapping + DISPLAY_RANGE = 4, //!< Debug tone mapping to validate scene exposure + }; + + class Builder : public BuilderBase { + friend struct BuilderDetails; + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + + Builder& toneMapping(ToneMapping toneMapping) noexcept; + + ColorGrading* build(Engine& engine); + + private: + friend class FColorGrading; + }; +}; + +} // namespace filament + +#endif // TNT_FILAMENT_COLOR_GRADING_H diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 8fb917f2fd..e93bceafd3 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -29,6 +29,7 @@ class JobSystem; namespace filament { class Camera; +class ColorGrading; class DebugRegistry; class Fence; class IndexBuffer; @@ -347,6 +348,7 @@ public: bool destroy(const Renderer* p); //!< Destroys a Renderer object. bool destroy(const Scene* p); //!< Destroys a Scene object. bool destroy(const Skybox* p); //!< Destroys a SkyBox object. + bool destroy(const ColorGrading* p); //!< Destroys a ColorGrading object. bool destroy(const SwapChain* p); //!< Destroys a SwapChain object. bool destroy(const Stream* p); //!< Destroys a Stream object. bool destroy(const Texture* p); //!< Destroys a Texture object. diff --git a/filament/src/Tonemapper.cpp b/filament/src/ColorGrading.cpp similarity index 51% rename from filament/src/Tonemapper.cpp rename to filament/src/ColorGrading.cpp index f52cc05b3e..b81392ac6d 100644 --- a/filament/src/Tonemapper.cpp +++ b/filament/src/ColorGrading.cpp @@ -14,20 +14,24 @@ * limitations under the License. */ -#include "details/Tonemapper.h" +#include "details/ColorGrading.h" #include "details/Engine.h" +#include "FilamentAPI-impl.h" + #include #include #include +#include + // When defined, the ACES tone mapper will match the brightness of the "ACES sRGB" tone mapper // It is *not* correct, but it helps for compatibility #define TONEMAP_ACES_MATCH_BRIGHTNESS -#include "ACES.h" +#include "ToneMapping.h" namespace filament { @@ -37,7 +41,46 @@ using namespace backend; static constexpr size_t LUT_DIMENSION = 32u; -Tonemapper::Tonemapper(FEngine& engine) { +struct ColorGrading::BuilderDetails { + ToneMapping mToneMapping = ToneMapping::ACES; +}; + +using BuilderType = ColorGrading; +BuilderType::Builder::Builder() noexcept = default; +BuilderType::Builder::~Builder() noexcept = default; +BuilderType::Builder::Builder(BuilderType::Builder const& rhs) noexcept = default; +BuilderType::Builder::Builder(BuilderType::Builder&& rhs) noexcept = default; +BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder const& rhs) noexcept = default; +BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder&& rhs) noexcept = default; + +ColorGrading::Builder& ColorGrading::Builder::toneMapping(ToneMapping toneMapping) noexcept { + mImpl->mToneMapping = toneMapping; + return *this; +} + +ColorGrading* ColorGrading::Builder::build(Engine& engine) { + return upcast(engine).createColorGrading(*this); +} + +using ToneMapper = float3(*)(float3); + +ToneMapper selectToneMapping(ColorGrading::ToneMapping toneMapping) { + switch(toneMapping) { + case ColorGrading::ToneMapping::LINEAR: + return tonemap::Linear; + case ColorGrading::ToneMapping::ACES: + return tonemap::ACES; + case ColorGrading::ToneMapping::FILMIC: + return tonemap::Filmic; + case ColorGrading::ToneMapping::REINHARD: + return tonemap::Reinhard; + case ColorGrading::ToneMapping::DISPLAY_RANGE: + return tonemap::DisplayRange; + } + return tonemap::ACES; +} + +FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) { SYSTRACE_CALL(); DriverApi& driver = engine.getDriverApi(); @@ -46,6 +89,8 @@ Tonemapper::Tonemapper(FEngine& engine) { constexpr size_t elementSize = sizeof(half4); void* const data = malloc(lutElementCount * elementSize); + ToneMapper toneMapper = selectToneMapping(builder->mToneMapping); + //auto now = std::chrono::steady_clock::now(); // Multithreadedly generate the tone mapping 3D look-up table using 32 jobs @@ -54,8 +99,8 @@ Tonemapper::Tonemapper(FEngine& engine) { JobSystem& js = engine.getJobSystem(); auto slices = js.createJob(); for (size_t b = 0; b < LUT_DIMENSION; b++) { - auto job = js.createJob(slices,[data, b](JobSystem&, JobSystem::Job*) { - half4* UTILS_RESTRICT p = (half4*)data + b * LUT_DIMENSION * LUT_DIMENSION; + auto job = js.createJob(slices, [data, b, toneMapper](JobSystem&, JobSystem::Job*) { + half4* UTILS_RESTRICT p = (half4*) data + b * LUT_DIMENSION * LUT_DIMENSION; for (size_t g = 0; g < LUT_DIMENSION; g++) { for (size_t r = 0; r < LUT_DIMENSION; r++) { float3 v = float3{ r, g, b } * (1.0f / (LUT_DIMENSION - 1u)); @@ -64,7 +109,7 @@ Tonemapper::Tonemapper(FEngine& engine) { v.y = lutToLinear(v.y); v.z = lutToLinear(v.z); // ACES tone mapping - v = tonemap_ACES(v); + v = toneMapper(v); // sRGB encoding v = image::linearTosRGB(v); *p++ = half4{ v, 0 }; @@ -93,99 +138,14 @@ Tonemapper::Tonemapper(FEngine& engine) { ); } -Tonemapper::~Tonemapper() noexcept = default; +FColorGrading::~FColorGrading() noexcept = default; -void Tonemapper::terminate(FEngine& engine) { +void FColorGrading::terminate(FEngine& engine) { DriverApi& driver = engine.getDriverApi(); driver.destroyTexture(mLutHandle); } -float3 Tonemapper::tonemap_Reinhard(float3 x) noexcept { - return x / (1.0f + dot(x, float3{ 0.2126f, 0.7152f, 0.0722f })); -} - -float3 Tonemapper::Tonemap_ACES_sRGB(float3 x) noexcept { - // Narkowicz 2015, "ACES Filmic Tone Mapping Curve" - const float a = 2.51f; - const float b = 0.03f; - const float c = 2.43f; - const float d = 0.59f; - const float e = 0.14f; - return (x * (a * x + b)) / (x * (c * x + d) + e); -} - -UTILS_ALWAYS_INLINE -float3 Tonemapper::tonemap_ACES(float3 x) noexcept { - return aces::ACES(x); -} - -float3 Tonemapper::tonemap_ACES_Rec2020_1k(float3 x) noexcept { - // Narkowicz 2016, "HDR Display – First Steps" - const float a = 15.8f; - const float b = 2.12f; - const float c = 1.2f; - const float d = 5.92f; - const float e = 1.9f; - return (x * (a * x + b)) / (x * (c * x + d) + e); -} - -/** - * Converts the input HDR RGB color into one of 16 debug colors that represent - * the pixel's exposure. When the output is cyan, the input color represents - * middle gray (18% exposure). Every exposure stop above or below middle gray - * causes a color shift. - * - * The relationship between exposures and colors is: - * - * -5EV - black - * -4EV - darkest blue - * -3EV - darker blue - * -2EV - dark blue - * -1EV - blue - * OEV - cyan - * +1EV - dark green - * +2EV - green - * +3EV - yellow - * +4EV - yellow-orange - * +5EV - orange - * +6EV - bright red - * +7EV - red - * +8EV - magenta - * +9EV - purple - * +10EV - white - */ -float3 Tonemapper::tonemap_DisplayRange(float3 x) noexcept { - // 16 debug colors + 1 duplicated at the end for easy indexing - - const float3 debugColors[17] = { - { 0.0, 0.0, 0.0 }, // black - { 0.0, 0.0, 0.1647 }, // darkest blue - { 0.0, 0.0, 0.3647 }, // darker blue - { 0.0, 0.0, 0.6647 }, // dark blue - { 0.0, 0.0, 0.9647 }, // blue - { 0.0, 0.9255, 0.9255 }, // cyan - { 0.0, 0.5647, 0.0 }, // dark green - { 0.0, 0.7843, 0.0 }, // green - { 1.0, 1.0, 0.0 }, // yellow - { 0.90588, 0.75294, 0.0 }, // yellow-orange - { 1.0, 0.5647, 0.0 }, // orange - { 1.0, 0.0, 0.0 }, // bright red - { 0.8392, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // magenta - { 0.6, 0.3333, 0.7882 }, // purple - { 1.0, 1.0, 1.0 }, // white - { 1.0, 1.0, 1.0 } // white - }; - - // The 5th color in the array (cyan) represents middle gray (18%) - // Every stop above or below middle gray causes a color shift - float v = log2(dot(x, float3{ 0.2126f, 0.7152f, 0.0722f }) / 0.18f); - v = clamp(v + 5.0f, 0.0f, 15.0f); - size_t index = size_t(v); - return mix(debugColors[index], debugColors[index + 1], v - float(index)); -} - -float Tonemapper::lutToLinear(float x) noexcept { +float FColorGrading::lutToLinear(float x) noexcept { // Alexa LogC EI 1000 curve const float ia = 1.0f / 5.555556f; const float b = 0.047996f; @@ -194,7 +154,7 @@ float Tonemapper::lutToLinear(float x) noexcept { return (std::pow(10.0f, (x - d) * ic) - b) * ia; } -float Tonemapper::linearToLut(float x) noexcept { +float FColorGrading::linearToLut(float x) noexcept { // Alexa LogC EI 1000 curve const float a = 5.555556f; const float b = 0.047996f; diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index aadb59340e..2c4158b7a3 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -196,6 +196,8 @@ void FEngine::init() { .irradiance(3, reinterpret_cast(sh)) .build(*this)); + mDefaultColorGrading = upcast(ColorGrading::Builder().build(*this)); + // Always initialize the default material, most materials' depth shaders fallback on it. mDefaultMaterial = upcast( FMaterial::DefaultMaterialBuilder() @@ -249,6 +251,8 @@ void FEngine::shutdown() { destroy(mDefaultIblTexture); destroy(mDefaultIbl); + destroy(mDefaultColorGrading); + destroy(mDefaultMaterial); /* @@ -262,6 +266,7 @@ void FEngine::shutdown() { cleanupResourceList(mViews); cleanupResourceList(mScenes); cleanupResourceList(mSkyboxes); + cleanupResourceList(mColorGradings); // this must be done after Skyboxes and before materials destroy(mSkyboxMaterial); @@ -531,6 +536,10 @@ FSkybox* FEngine::createSkybox(const Skybox::Builder& builder) noexcept { return create(mSkyboxes, builder); } +FColorGrading* FEngine::createColorGrading(const ColorGrading::Builder& builder) noexcept { + return create(mColorGradings, builder); +} + FStream* FEngine::createStream(const Stream::Builder& builder) noexcept { return create(mStreams, builder); } @@ -694,6 +703,10 @@ inline bool FEngine::destroy(const FSkybox* p) { return terminateAndDestroy(p, mSkyboxes); } +inline bool FEngine::destroy(const FColorGrading* p) { + return terminateAndDestroy(p, mColorGradings); +} + UTILS_NOINLINE bool FEngine::destroy(const FTexture* p) { return terminateAndDestroy(p, mTextures); @@ -896,6 +909,10 @@ bool Engine::destroy(const Skybox* p) { return upcast(this)->destroy(upcast(p)); } +bool Engine::destroy(const ColorGrading* p) { + return upcast(this)->destroy(upcast(p)); +} + bool Engine::destroy(const Stream* p) { return upcast(this)->destroy(upcast(p)); } diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index d06ffee7a1..130adc4803 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -27,7 +27,7 @@ #include "details/Material.h" #include "details/MaterialInstance.h" #include "details/Texture.h" -#include "details/Tonemapper.h" +#include "details/ColorGrading.h" #include "generated/resources/materials.h" #include @@ -184,8 +184,6 @@ void PostProcessManager::init() noexcept { *static_cast(dataZero.buffer) = 0; driver.update2DImage(mDummyOneTexture, 0, 0, 0, 1, 1, std::move(dataOne)); driver.update2DImage(mDummyZeroTexture, 0, 0, 0, 1, 1, std::move(dataZero)); - - mTonemapper = new Tonemapper(mEngine); } void PostProcessManager::terminate(DriverApi& driver) noexcept { @@ -206,8 +204,6 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept { mFxaa.terminate(engine); mDoFBlur.terminate(engine); mDoF.terminate(engine); - mTonemapper->terminate(engine); - delete mTonemapper; } // ------------------------------------------------------------------------------------------------ @@ -983,7 +979,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver, Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); FMaterialInstance* mi = mColorGradingAsSubpass.getMaterialInstance(); - mi->setParameter("lut", mTonemapper->getHwHandle(), { + mi->setParameter("lut", mEngine.getDefaultColorGrading()->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR }); @@ -992,7 +988,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver, mi->commit(driver); mi->use(driver); const uint8_t variant = uint8_t(translucent ? - PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); + PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE); driver.draw(mColorGradingAsSubpass.getPipelineState(variant), fullScreenRenderPrimitive); } @@ -1005,7 +1001,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, FEngine& engine = mEngine; Handle const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive(); - struct PostProcessToneMapping { + struct PostProcessColorGrading { FrameGraphId input; FrameGraphId output; FrameGraphId bloom; @@ -1031,17 +1027,17 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, } } - auto& ppToneMapping = fg.addPass("tonemapping", + auto& ppColorGrading = fg.addPass("colorGrading", [&](FrameGraph::Builder& builder, auto& data) { auto const& inputDesc = fg.getDescriptor(input); data.input = builder.sample(input); - data.output = builder.createTexture("tonemapping output", { + data.output = builder.createTexture("colorGrading output", { .width = inputDesc.width, .height = inputDesc.height, .format = outFormat }); data.output = builder.write(data.output); - data.rt = builder.createRenderTarget("ToneMapping Target", { + data.rt = builder.createRenderTarget("colorGrading Target", { .attachments = { data.output } }); if (bloomBlur.isValid()) { @@ -1063,7 +1059,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, data.dirt.isValid() ? resources.getTexture(data.dirt) : getOneTexture(); FMaterialInstance* mi = mColorGrading.getMaterialInstance(); - mi->setParameter("lut", mTonemapper->getHwHandle(), { + mi->setParameter("lut", mEngine.getDefaultColorGrading()->getHwHandle(), { .filterMag = SamplerMagFilter::LINEAR, .filterMin = SamplerMinFilter::LINEAR }); @@ -1100,9 +1096,10 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg, driver.beginRenderPass(target.target, target.params); driver.draw(mColorGrading.getPipelineState(variant), fullScreenRenderPrimitive); driver.endRenderPass(); - }); + } + ); - return ppToneMapping.getData().output; + return ppColorGrading.getData().output; } FrameGraphId PostProcessManager::fxaa(FrameGraph& fg, diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index 06d20bb5f1..2993015ed5 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -33,7 +33,6 @@ class FMaterial; class FMaterialInstance; class FView; class RenderPass; -class Tonemapper; struct CameraInfo; class PostProcessManager { @@ -170,9 +169,6 @@ private: backend::Handle mDummyZeroTexture; size_t mSeparableGaussianBlurKernelStorageSize = 0; - - // eventually this will be a separate object - Tonemapper* mTonemapper = nullptr; }; } // namespace filament diff --git a/filament/src/ACES.h b/filament/src/ToneMapping.h similarity index 69% rename from filament/src/ACES.h rename to filament/src/ToneMapping.h index 9ad0005c3a..a19c80ce37 100644 --- a/filament/src/ACES.h +++ b/filament/src/ToneMapping.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_ACES_H -#define TNT_FILAMENT_ACES_H +#ifndef TNT_FILAMENT_TONE_MAPPING_H +#define TNT_FILAMENT_TONE_MAPPING_H #include @@ -24,10 +24,15 @@ #include namespace filament { -namespace aces { using namespace math; +//------------------------------------------------------------------------------ +// ACES operations, from https://github.com/ampas/aces-dev +//------------------------------------------------------------------------------ + +namespace aces { + inline float rgb_2_saturation(float3 rgb) { // Input: ACES // Output: OCES @@ -146,7 +151,6 @@ inline float3 darkSurround_to_dimSurround(float3 linearCV) { UTILS_ALWAYS_INLINE inline float3 ACES(float3 color) { - // From https://github.com/ampas/aces-dev // Some bits were removed to adapt to our desired output // Input: linear sRGB // Output: linear sRGB @@ -233,6 +237,94 @@ inline float3 ACES(float3 color) { } } // namespace aces + +//------------------------------------------------------------------------------ +// Tone mapping operators +//------------------------------------------------------------------------------ + +namespace tonemap { + +UTILS_ALWAYS_INLINE +float3 Linear(float3 x) noexcept { + return x; +} + +float3 Reinhard(float3 x) noexcept { + return x / (1.0f + dot(x, float3{0.2126f, 0.7152f, 0.0722f})); +} + +float3 Filmic(float3 x) noexcept { + // Narkowicz 2015, "ACES Filmic Tone Mapping Curve" + const float a = 2.51f; + const float b = 0.03f; + const float c = 2.43f; + const float d = 0.59f; + const float e = 0.14f; + return (x * (a * x + b)) / (x * (c * x + d) + e); +} + +float3 ACES(float3 x) noexcept { + return aces::ACES(x); +} + +/** + * Converts the input HDR RGB color into one of 16 debug colors that represent + * the pixel's exposure. When the output is cyan, the input color represents + * middle gray (18% exposure). Every exposure stop above or below middle gray + * causes a color shift. + * + * The relationship between exposures and colors is: + * + * -5EV - black + * -4EV - darkest blue + * -3EV - darker blue + * -2EV - dark blue + * -1EV - blue + * OEV - cyan + * +1EV - dark green + * +2EV - green + * +3EV - yellow + * +4EV - yellow-orange + * +5EV - orange + * +6EV - bright red + * +7EV - red + * +8EV - magenta + * +9EV - purple + * +10EV - white + */ +float3 DisplayRange(float3 x) noexcept { + // 16 debug colors + 1 duplicated at the end for easy indexing + + const float3 debugColors[17] = { + {0.0, 0.0, 0.0}, // black + {0.0, 0.0, 0.1647}, // darkest blue + {0.0, 0.0, 0.3647}, // darker blue + {0.0, 0.0, 0.6647}, // dark blue + {0.0, 0.0, 0.9647}, // blue + {0.0, 0.9255, 0.9255}, // cyan + {0.0, 0.5647, 0.0}, // dark green + {0.0, 0.7843, 0.0}, // green + {1.0, 1.0, 0.0}, // yellow + {0.90588, 0.75294, 0.0}, // yellow-orange + {1.0, 0.5647, 0.0}, // orange + {1.0, 0.0, 0.0}, // bright red + {0.8392, 0.0, 0.0}, // red + {1.0, 0.0, 1.0}, // magenta + {0.6, 0.3333, 0.7882}, // purple + {1.0, 1.0, 1.0}, // white + {1.0, 1.0, 1.0} // white + }; + + // The 5th color in the array (cyan) represents middle gray (18%) + // Every stop above or below middle gray causes a color shift + float v = log2(dot(x, float3{0.2126f, 0.7152f, 0.0722f}) / 0.18f); + v = clamp(v + 5.0f, 0.0f, 15.0f); + size_t index = size_t(v); + return mix(debugColors[index], debugColors[index + 1], v - float(index)); +} + +} // namespace tonemap + } // namespace filament -#endif //TNT_FILAMENT_ACES_H +#endif //TNT_FILAMENT_TONE_MAPPING_H diff --git a/filament/src/details/Tonemapper.h b/filament/src/details/ColorGrading.h similarity index 62% rename from filament/src/details/Tonemapper.h rename to filament/src/details/ColorGrading.h index 58e3aa6189..f5c8e3ab1f 100644 --- a/filament/src/details/Tonemapper.h +++ b/filament/src/details/ColorGrading.h @@ -14,21 +14,27 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_DETAILS_TONEMAPPER_H -#define TNT_FILAMENT_DETAILS_TONEMAPPER_H +#ifndef TNT_FILAMENT_DETAILS_COLORGRADING_H +#define TNT_FILAMENT_DETAILS_COLORGRADING_H + +#include "upcast.h" #include #include +#include + namespace filament { class FEngine; -class Tonemapper { +class FColorGrading : public ColorGrading { public: - Tonemapper(FEngine& engine); + FColorGrading(FEngine& engine, const Builder& builder); + FColorGrading(const FColorGrading& rhs) = delete; + FColorGrading& operator=(const FColorGrading& rhs) = delete; - ~Tonemapper() noexcept; + ~FColorGrading() noexcept; // frees driver resources, object becomes invalid void terminate(FEngine& engine); @@ -36,22 +42,14 @@ public: backend::TextureHandle getHwHandle() const noexcept { return mLutHandle; } private: - static inline math::float3 tonemap_Reinhard(math::float3 x) noexcept; - static inline math::float3 Tonemap_ACES_sRGB(math::float3 x) noexcept; - static inline math::float3 tonemap_ACES(math::float3 x) noexcept; - - // Operators for HDR output - static inline math::float3 tonemap_ACES_Rec2020_1k(math::float3 x) noexcept; - - // Operators for debugging - static inline math::float3 tonemap_DisplayRange(math::float3 x) noexcept; - static inline float lutToLinear(float x) noexcept; static inline float linearToLut(float x) noexcept; backend::TextureHandle mLutHandle; }; +FILAMENT_UPCAST(ColorGrading) + } // namespace filament -#endif //TNT_FILAMENT_DETAILS_TONEMAPPER_H +#endif //TNT_FILAMENT_DETAILS_COLORGRADING_H diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 66e8dd9b79..4513201f2e 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -32,6 +32,7 @@ #include "details/IndexBuffer.h" #include "details/RenderTarget.h" #include "details/ResourceList.h" +#include "details/ColorGrading.h" #include "details/Skybox.h" #include "private/backend/CommandStream.h" @@ -47,6 +48,7 @@ #include #include #include +#include #include #include @@ -150,6 +152,7 @@ public: const FMaterial* getSkyboxMaterial() const noexcept; const FIndirectLight* getDefaultIndirectLight() const noexcept { return mDefaultIbl; } const FTexture* getDummyCubemap() const noexcept { return mDefaultIblTexture; } + const FColorGrading* getDefaultColorGrading() const noexcept { return mDefaultColorGrading; } backend::Handle getFullScreenRenderPrimitive() const noexcept { return mFullScreenTriangleRph; @@ -220,6 +223,7 @@ public: FMaterial* createMaterial(const Material::Builder& builder) noexcept; FTexture* createTexture(const Texture::Builder& builder) noexcept; FSkybox* createSkybox(const Skybox::Builder& builder) noexcept; + FColorGrading* createColorGrading(const ColorGrading::Builder& builder) noexcept; FStream* createStream(const Stream::Builder& builder) noexcept; FRenderTarget* createRenderTarget(const RenderTarget::Builder& builder) noexcept; @@ -249,6 +253,7 @@ public: bool destroy(const FRenderer* p); bool destroy(const FScene* p); bool destroy(const FSkybox* p); + bool destroy(const FColorGrading* p); bool destroy(const FStream* p); bool destroy(const FTexture* p); bool destroy(const FRenderTarget* p); @@ -337,6 +342,7 @@ private: ResourceList mMaterials{ "Material" }; ResourceList mTextures{ "Texture" }; ResourceList mSkyboxes{ "Skybox" }; + ResourceList mColorGradings{ "ColorGrading" }; ResourceList mRenderTargets{ "RenderTarget" }; mutable uint32_t mMaterialId = 0; @@ -363,6 +369,8 @@ private: mutable FTexture* mDefaultIblTexture = nullptr; mutable FIndirectLight* mDefaultIbl = nullptr; + mutable FColorGrading* mDefaultColorGrading = nullptr; + mutable utils::CountDownLatch mDriverBarrier; mutable filaflat::ShaderBuilder mVertexShaderBuilder;