Introduce ColorGrading API (#2613)

* Introduce ColorGrading API

A ColorGrading object will eventually be settable on a View to
choose the tone mapping and other color transformations.

There is currently only a single default ColorGrading instance
used by all views.

* Use raw function pointers
This commit is contained in:
Romain Guy
2020-05-29 18:54:48 -07:00
committed by GitHub
parent 1f77fb5995
commit b77e024de9
11 changed files with 282 additions and 137 deletions

View File

@@ -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())];

View File

@@ -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)

View File

@@ -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 <filament/FilamentAPI.h>
#include <utils/compiler.h>
#include <math/mathfwd.h>
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<BuilderDetails> {
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

View File

@@ -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.

View File

@@ -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 <image/ColorTransform.h>
#include <utils/JobSystem.h>
#include <utils/Systrace.h>
#include <functional>
// 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;

View File

@@ -196,6 +196,8 @@ void FEngine::init() {
.irradiance(3, reinterpret_cast<const float3*>(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));
}

View File

@@ -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 <private/filament/SibGenerator.h>
@@ -184,8 +184,6 @@ void PostProcessManager::init() noexcept {
*static_cast<uint32_t *>(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<HwRenderPrimitive> 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<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
FEngine& engine = mEngine;
Handle<HwRenderPrimitive> const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive();
struct PostProcessToneMapping {
struct PostProcessColorGrading {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
FrameGraphId<FrameGraphTexture> bloom;
@@ -1031,17 +1027,17 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
}
}
auto& ppToneMapping = fg.addPass<PostProcessToneMapping>("tonemapping",
auto& ppColorGrading = fg.addPass<PostProcessColorGrading>("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<FrameGraphTexture> 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<FrameGraphTexture> 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<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,

View File

@@ -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<backend::HwTexture> mDummyZeroTexture;
size_t mSeparableGaussianBlurKernelStorageSize = 0;
// eventually this will be a separate object
Tonemapper* mTonemapper = nullptr;
};
} // namespace filament

View File

@@ -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 <utils/compiler.h>
@@ -24,10 +24,15 @@
#include <math/scalar.h>
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

View File

@@ -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 <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <filament/ColorGrading.h>
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

View File

@@ -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 <filament/Material.h>
#include <filament/MaterialEnums.h>
#include <filament/Texture.h>
#include <filament/ColorGrading.h>
#include <filament/Skybox.h>
#include <filament/Stream.h>
@@ -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<backend::HwRenderPrimitive> 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<FMaterial> mMaterials{ "Material" };
ResourceList<FTexture> mTextures{ "Texture" };
ResourceList<FSkybox> mSkyboxes{ "Skybox" };
ResourceList<FColorGrading> mColorGradings{ "ColorGrading" };
ResourceList<FRenderTarget> 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;