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:
@@ -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())];
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
65
filament/include/filament/ColorGrading.h
Normal file
65
filament/include/filament/ColorGrading.h
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user