Add channel mixer and docs to ColorGrading (#2618)
This commit is contained in:
@@ -30,17 +30,62 @@ namespace filament {
|
||||
class Engine;
|
||||
class FColorGrading;
|
||||
|
||||
/**
|
||||
* ColorGrading is used to transform (either to modify or correct) the colors of the HDR buffer
|
||||
* rendered by Filament. Color grading transforms are applied after lighting, and after any lens
|
||||
* effects (bloom for instance), and include tone mapping.
|
||||
*
|
||||
* Creation, usage and destruction
|
||||
* ===============================
|
||||
*
|
||||
* A ColorGrading object is created using the ColorGrading::Builder and destroyed by calling
|
||||
* Engine::destroy(const ColorGrading*). A ColorGrading object is meant to be set on a View.
|
||||
*
|
||||
* ~~~~~~~~~~~{.cpp}
|
||||
* filament::Engine* engine = filament::Engine::create();
|
||||
*
|
||||
* filament::ColorGrading* colorGrading = filament::ColorGrading::Builder()
|
||||
* .toneMapping(filament::ColorGrading::ToneMapping::ACES)
|
||||
* .build(*engine);
|
||||
*
|
||||
* myView->setColorGrading(colorGrading);
|
||||
*
|
||||
* engine->destroy(colorGrading);
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
* Performance
|
||||
* ===========
|
||||
*
|
||||
* Creating a new ColorGrading object may be more expensive than other Filament objects as a
|
||||
* 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on
|
||||
* the CPU.
|
||||
*
|
||||
* Defaults
|
||||
* ========
|
||||
*
|
||||
* Here are the default color grading options:
|
||||
* - Tone mapping: ACES
|
||||
* - White balance: temperature 0, and tint 0
|
||||
* - Channel mixer: red {1,0,0}, green {0,1,0}, blue {0,0,1}
|
||||
*
|
||||
* @see View
|
||||
*/
|
||||
class UTILS_PUBLIC ColorGrading : public FilamentAPI {
|
||||
struct BuilderDetails;
|
||||
public:
|
||||
|
||||
/**
|
||||
* List of available tone-mapping operators.
|
||||
*/
|
||||
enum class ToneMapping : uint8_t {
|
||||
LINEAR = 0, //!< Linear tone mapping (i.e. no tone mapping)
|
||||
ACES = 1, //!< ACES tone mapping, with a brightness modifier
|
||||
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
|
||||
DISPLAY_RANGE = 4, //!< Tone mapping used to validate/debug scene exposure
|
||||
};
|
||||
|
||||
//! Use Builder to construct a ColorGrading object instance
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
friend struct BuilderDetails;
|
||||
public:
|
||||
@@ -51,11 +96,82 @@ public:
|
||||
Builder& operator=(Builder const& rhs) noexcept;
|
||||
Builder& operator=(Builder&& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* Selects the tone mapping operator to apply to the HDR color buffer as the last
|
||||
* operation of the color grading post-processing step.
|
||||
*
|
||||
* The default tone mapping operator is ACES.
|
||||
*
|
||||
* @param toneMapping The tone mapping operator to apply to the HDR color buffer
|
||||
*
|
||||
* @return This Builder, for chaining calls
|
||||
*/
|
||||
Builder& toneMapping(ToneMapping toneMapping) noexcept;
|
||||
|
||||
// TODO: document: temperature from -1 to +1, tint from -1 to +1; clipped otherwise
|
||||
/**
|
||||
* Adjusts the while balance of the image. This can be used to remove color casts
|
||||
* and correct the appearance of the white point in the scene, or to alter the
|
||||
* overall chromaticity of the image for artistic reasons (to make the image appear
|
||||
* cooler or warmer for instance).
|
||||
*
|
||||
* The while balance adjustment is defined with two values:
|
||||
* - Temperature, to modify the color temperature. This value will modify the colors
|
||||
* on a blue/yellow axis. Lower values apply a cool color temperature, and higher
|
||||
* values apply a warm color temperature. The lowest value, -1.0f, is equivalent to
|
||||
* a temperature of 2,000K. The highest value, 1.0f, is equivalent to a temperature
|
||||
* of 50,000K.
|
||||
* - Tint, to modify the colors on a green/magenta axis. The lowest value, -1.0f, will
|
||||
* apply a strong green cast, and the highest value, 1.0f, will apply a strong magenta
|
||||
* cast.
|
||||
*
|
||||
* Both values are expected to be in the range [-1.0..+1.0]. Values outside of that
|
||||
* range will be clipped to that range.
|
||||
*
|
||||
* @param temperature Modification on the blue/yellow axis, as a value between -1.0 and +1.0.
|
||||
* @param tint Modification on the green/magenta axis, as a value between -1.0 and +1.0.
|
||||
*
|
||||
* @return This Builder, for chaining calls
|
||||
*/
|
||||
Builder& whiteBalance(float temperature, float tint) noexcept;
|
||||
|
||||
/**
|
||||
* The channel mixer adjustment modifies each output color channel using the specified
|
||||
* mix of the source color channels.
|
||||
*
|
||||
* By default each output color channel is set to use 100% of the corresponding source
|
||||
* channel and 0% of the other channels. For instance, the output red channel is set to
|
||||
* {1.0, 0.0, 1.0} or 100% red, 0% green and 0% blue.
|
||||
*
|
||||
* Each output channel can add or subtract data from the source channel by using values
|
||||
* in the range [-2.0..+2.0]. Values outside of that range will be clipped to that range.
|
||||
*
|
||||
* Using the channel mixer adjustment you can for instance create a monochrome output
|
||||
* by setting all 3 output channels to the same mix. For instance: {0.4, 0.4, 0.2} for
|
||||
* all 3 output channels(40% red, 40% green and 20% blue).
|
||||
*
|
||||
* More complex mixes can be used to create more compelx effects. For instance, here is
|
||||
* a mix that creates a sepia tone effect:
|
||||
* - outRed = {0.255, 0.858, 0.087}
|
||||
* - outGreen = {0.213, 0.715, 0.072}
|
||||
* - outBlue = {0.170, 0.572, 0.058}
|
||||
*
|
||||
* @param outRed The mix of source RGB for the output red channel, between -2.0 and +2.0
|
||||
* @param outGreen The mix of source RGB for the output green channel, between -2.0 and +2.0
|
||||
* @param outBlue The mix of source RGB for the output blue channel, between -2.0 and +2.0
|
||||
*
|
||||
* @return This Builder, for chaining calls
|
||||
*/
|
||||
Builder& channelMixer(
|
||||
math::float3 outRed, math::float3 outGreen, math::float3 outBlue) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the ColorGrading object and returns a pointer to it.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine to associate this ColorGrading with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occurred.
|
||||
*/
|
||||
ColorGrading* build(Engine& engine);
|
||||
|
||||
private:
|
||||
|
||||
@@ -622,7 +622,7 @@ public:
|
||||
*
|
||||
* @param enabled true enables post processing, false disables it.
|
||||
*
|
||||
* @see setBloomOptions, setToneMapping, setAntiAliasing, setDithering, setSampleCount
|
||||
* @see setBloomOptions, setColorGrading, setAntiAliasing, setDithering, setSampleCount
|
||||
*/
|
||||
void setPostProcessingEnabled(bool enabled) noexcept;
|
||||
|
||||
|
||||
@@ -18,9 +18,15 @@
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include "ColorSpace.h"
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include "ColorSpace.h"
|
||||
// When defined, the ACES tone mapper will match the brightness of the filmic ("ACES sRGB")
|
||||
// tone mapper. It is *not* correct, but it helps for compatibility
|
||||
// TODO: Always enable this, expose a float to control this (1.0 == real ACES)
|
||||
#define TONEMAP_ACES_MATCH_BRIGHTNESS
|
||||
#include "ToneMapping.h"
|
||||
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
@@ -31,13 +37,6 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
// When defined, the ACES tone mapper will match the brightness of the filmic ("ACES sRGB")
|
||||
// tone mapper. It is *not* correct, but it helps for compatibility
|
||||
// TODO: Always enable this, expose a float to control this (1.0 == real ACES)
|
||||
#define TONEMAP_ACES_MATCH_BRIGHTNESS
|
||||
|
||||
#include "ToneMapping.h"
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace utils;
|
||||
@@ -52,7 +51,10 @@ static constexpr size_t LUT_DIMENSION = 32u;
|
||||
|
||||
struct ColorGrading::BuilderDetails {
|
||||
ToneMapping toneMapping = ToneMapping::ACES;
|
||||
float2 whiteBalance = {0.0f, 0.0f};
|
||||
float2 whiteBalance = {0.0f, 0.0f};
|
||||
float3 outRed = {1.0f, 0.0f, 0.0f};
|
||||
float3 outGreen = {0.0f, 1.0f, 0.0f};
|
||||
float3 outBlue = {0.0f, 0.0f, 1.0f};
|
||||
};
|
||||
|
||||
using BuilderType = ColorGrading;
|
||||
@@ -76,30 +78,16 @@ ColorGrading::Builder& ColorGrading::Builder::whiteBalance(float temperature, fl
|
||||
return *this;
|
||||
}
|
||||
|
||||
ColorGrading* ColorGrading::Builder::build(Engine& engine) {
|
||||
return upcast(engine).createColorGrading(*this);
|
||||
ColorGrading::Builder& ColorGrading::Builder::channelMixer(
|
||||
float3 outRed, float3 outGreen, float3 outBlue) noexcept {
|
||||
mImpl->outRed = clamp(outRed, -2.0f, 2.0f);
|
||||
mImpl->outGreen = clamp(outGreen, -2.0f, 2.0f);
|
||||
mImpl->outBlue = clamp(outBlue, -2.0f, 2.0f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tone mapping
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
ColorGrading* ColorGrading::Builder::build(Engine& engine) {
|
||||
return upcast(engine).createColorGrading(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -132,13 +120,54 @@ inline float3 chromaticAdaptation(float3 v, float2 whiteBalance) {
|
||||
return v;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// General color grading
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
mat3f selectColorGradingTransform(ColorGrading::ToneMapping toneMapping) {
|
||||
switch (toneMapping) {
|
||||
case ColorGrading::ToneMapping::ACES:
|
||||
return sRGB_to_AP1;
|
||||
default:
|
||||
return mat3f{};
|
||||
}
|
||||
return mat3f{};
|
||||
}
|
||||
|
||||
UTILS_ALWAYS_INLINE
|
||||
inline constexpr float3 channelMixer(float3 v, float3 r, float3 g, float3 b) {
|
||||
return {dot(v, r), dot(v, g), dot(v, b)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tone mapping
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Color grading implementation
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct Config {
|
||||
mat3f colorGradingTransform;
|
||||
ToneMapper toneMapper;
|
||||
float2 whiteBalance;
|
||||
};
|
||||
|
||||
FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
@@ -151,8 +180,8 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
void* const data = malloc(lutElementCount * elementSize);
|
||||
|
||||
Config config{
|
||||
.toneMapper = selectToneMapping(builder->toneMapping),
|
||||
.whiteBalance = builder->whiteBalance
|
||||
.colorGradingTransform = selectColorGradingTransform(builder->toneMapping),
|
||||
.toneMapper = selectToneMapping(builder->toneMapping),
|
||||
};
|
||||
|
||||
//auto now = std::chrono::steady_clock::now();
|
||||
@@ -163,7 +192,7 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
auto slices = js.createJob();
|
||||
for (size_t b = 0; b < LUT_DIMENSION; b++) {
|
||||
auto job = js.createJob(slices, [data, b, config](JobSystem&, JobSystem::Job*) {
|
||||
auto job = js.createJob(slices, [data, b, &config, builder](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++) {
|
||||
@@ -173,15 +202,26 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
v = lutToLinear(v);
|
||||
|
||||
// White balance
|
||||
v = chromaticAdaptation(v, config.whiteBalance);
|
||||
v = chromaticAdaptation(v, builder->whiteBalance);
|
||||
|
||||
// Convert to color grading color space
|
||||
v = config.colorGradingTransform * v;
|
||||
|
||||
// Channel mixer
|
||||
v = channelMixer(v, builder->outRed, builder->outGreen, builder->outBlue);
|
||||
|
||||
// Kill negative values before tone mapping
|
||||
v = max(v, 0.0f);
|
||||
|
||||
// Tone mapping
|
||||
v = config.toneMapper(v);
|
||||
|
||||
// TODO: allow to customize the output color space
|
||||
// Apply OECF
|
||||
// TODO: allow to customize the output color space,
|
||||
// here we assume we are in the sRGB gamut already
|
||||
v = image::linearTosRGB(v);
|
||||
|
||||
*p++ = half4{ v, 0 };
|
||||
*p++ = half4{v, 0.0f};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -54,6 +54,42 @@ constexpr mat3f CIECAT02_to_XYZ{
|
||||
0.1827450f, 0.0720978f, 1.0153300f
|
||||
};
|
||||
|
||||
constexpr mat3f AP1_to_XYZ{
|
||||
0.6624541811f, 0.2722287168f, -0.0055746495f,
|
||||
0.1340042065f, 0.6740817658f, 0.0040607335f,
|
||||
0.1561876870f, 0.0536895174f, 1.0103391003f
|
||||
};
|
||||
|
||||
constexpr mat3f XYZ_to_AP1{
|
||||
1.6410233797f, -0.6636628587f, 0.0117218943f,
|
||||
-0.3248032942f, 1.6153315917f, -0.0082844420f,
|
||||
-0.2364246952f, 0.0167563477f, 0.9883948585f
|
||||
};
|
||||
|
||||
constexpr mat3f AP1_to_AP0{
|
||||
0.6954522414f, 0.0447945634f, -0.0055258826f,
|
||||
0.1406786965f, 0.8596711185f, 0.0040252103f,
|
||||
0.1638690622f, 0.0955343182f, 1.0015006723f
|
||||
};
|
||||
|
||||
constexpr mat3f AP0_to_AP1{
|
||||
1.4514393161f, -0.0765537734f, 0.0083161484f,
|
||||
-0.2365107469f, 1.1762296998f, -0.0060324498f,
|
||||
-0.2149285693f, -0.0996759264f, 0.9977163014f
|
||||
};
|
||||
|
||||
constexpr mat3f AP1_to_sRGB{
|
||||
1.70505f, -0.13026f, -0.02400f,
|
||||
-0.62179f, 1.14080f, -0.12897f,
|
||||
-0.08326f, -0.01055f, 1.15297f
|
||||
};
|
||||
|
||||
constexpr mat3f sRGB_to_AP1{
|
||||
0.61319f, 0.07021f, 0.02062f,
|
||||
0.33951f, 0.91634f, 0.10957f,
|
||||
0.04737f, 0.01345f, 0.86961f
|
||||
};
|
||||
|
||||
// Standard CIE 1931 2° illuminant D65, in xyY space
|
||||
constexpr float3 ILLUMINANT_D65_xyY{0.31271f, 0.32902f, 1.0f};
|
||||
|
||||
@@ -66,7 +102,12 @@ constexpr mat3f sRGB_to_LMS = XYZ_to_CIECAT02 * sRGB_to_XYZ;
|
||||
constexpr mat3f LMS_to_sRGB = XYZ_to_sRGB * CIECAT02_to_XYZ;
|
||||
|
||||
inline constexpr XYZ xyY_to_XYZ(xyY v) {
|
||||
return XYZ{v.x / v.y, v.z, (1.0f - v.x - v.y) / v.y};
|
||||
const float a = v.z / max(v.y, 1e-5f);
|
||||
return XYZ{v.x * a, v.z, (1.0f - v.x - v.y) * a};
|
||||
}
|
||||
|
||||
inline constexpr xyY XYZ_to_xyY(XYZ v) {
|
||||
return float3(v.xy / max(v.x + v.y + v.z, 1e-5f), v.y);
|
||||
}
|
||||
|
||||
// Returns the y chromaticity coordinate in xyY for an illuminant series D,
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_TONE_MAPPING_H
|
||||
#define TNT_FILAMENT_TONE_MAPPING_H
|
||||
|
||||
#include "ColorSpace.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <math/mat3.h>
|
||||
@@ -111,68 +113,25 @@ inline float center_hue(float hue, float centerH) {
|
||||
return hueCentered;
|
||||
}
|
||||
|
||||
inline float3 XYZ_2_xyY(float3 XYZ) {
|
||||
float divisor = max(XYZ.x + XYZ.y + XYZ.z, 1e-5f);
|
||||
return float3(XYZ.xy / divisor, XYZ.y);
|
||||
}
|
||||
|
||||
inline float3 xyY_2_XYZ(float3 xyY) {
|
||||
float a = xyY.z / max(xyY.y, 1e-5f);
|
||||
float3 XYZ = float3(float2{ xyY.x, xyY.z }, (1.0f - xyY.x - xyY.y));
|
||||
XYZ.x *= a;
|
||||
XYZ.z *= a;
|
||||
return XYZ;
|
||||
}
|
||||
|
||||
inline float3 darkSurround_to_dimSurround(float3 linearCV) {
|
||||
const float DIM_SURROUND_GAMMA = 0.9811f;
|
||||
|
||||
const mat3f AP1_2_XYZ{
|
||||
0.6624541811f, 0.2722287168f, -0.0055746495f,
|
||||
0.1340042065f, 0.6740817658f, 0.0040607335f,
|
||||
0.1561876870f, 0.0536895174f, 1.0103391003f
|
||||
};
|
||||
|
||||
const mat3f XYZ_2_AP1{
|
||||
1.6410233797f, -0.6636628587f, 0.0117218943f,
|
||||
-0.3248032942f, 1.6153315917f, -0.0082844420f,
|
||||
-0.2364246952f, 0.0167563477f, 0.9883948585f
|
||||
};
|
||||
|
||||
float3 XYZ = AP1_2_XYZ * linearCV;
|
||||
float3 xyY = XYZ_2_xyY(XYZ);
|
||||
float3 XYZ = AP1_to_XYZ * linearCV;
|
||||
float3 xyY = XYZ_to_xyY(XYZ);
|
||||
|
||||
xyY.z = clamp(xyY.z, 0.0f, (float)std::numeric_limits<math::half>::max());
|
||||
xyY.z = std::pow(xyY.z, DIM_SURROUND_GAMMA);
|
||||
|
||||
XYZ = xyY_2_XYZ(xyY);
|
||||
return XYZ_2_AP1 * XYZ;
|
||||
XYZ = xyY_to_XYZ(xyY);
|
||||
return XYZ_to_AP1 * XYZ;
|
||||
}
|
||||
|
||||
UTILS_ALWAYS_INLINE
|
||||
inline float3 ACES(float3 color) {
|
||||
// Some bits were removed to adapt to our desired output
|
||||
// Input: linear sRGB
|
||||
// Input: ACEScg (AP1)
|
||||
// Output: linear sRGB
|
||||
|
||||
const mat3f sRGB_2_AP0{
|
||||
0.439701f, 0.0897923f, 0.017544f,
|
||||
0.382978f, 0.8134230f, 0.111544f,
|
||||
0.177335f, 0.0967616f, 0.870704f
|
||||
};
|
||||
|
||||
const mat3f AP0_2_AP1{
|
||||
1.4514393161f, -0.0765537734f, 0.0083161484f,
|
||||
-0.2365107469f, 1.1762296998f, -0.0060324498f,
|
||||
-0.2149285693f, -0.0996759264f, 0.9977163014f
|
||||
};
|
||||
|
||||
const mat3f AP1_2_sRGB{
|
||||
1.70505f, -0.13026f, -0.024f,
|
||||
-0.62179f, 1.1408f, -0.12897f,
|
||||
-0.08326f, -0.01055f, 1.15297f
|
||||
};
|
||||
|
||||
// "Glow" module constants
|
||||
const float RRT_GLOW_GAIN = 0.05f;
|
||||
const float RRT_GLOW_MID = 0.08f;
|
||||
@@ -187,8 +146,7 @@ inline float3 ACES(float3 color) {
|
||||
const float RRT_SAT_FACTOR = 0.96f;
|
||||
const float ODT_SAT_FACTOR = 0.93f;
|
||||
|
||||
// This assumes our working color space is sRGB
|
||||
float3 ap0 = sRGB_2_AP0 * color;
|
||||
float3 ap0 = AP1_to_AP0 * color;
|
||||
|
||||
// Glow module
|
||||
float saturation = rgb_2_saturation(ap0);
|
||||
@@ -206,7 +164,7 @@ inline float3 ACES(float3 color) {
|
||||
ap0.r += hueWeight * saturation * (RRT_RED_PIVOT - ap0.r) * (1.0f - RRT_RED_SCALE);
|
||||
|
||||
// ACES to RGB rendering space
|
||||
float3 ap1 = clamp(AP0_2_AP1 * ap0, 0.0f, (float)std::numeric_limits<math::half>::max());
|
||||
float3 ap1 = clamp(AP0_to_AP1 * ap0, 0.0f, (float)std::numeric_limits<math::half>::max());
|
||||
|
||||
// Global desaturation
|
||||
const float3 AP1_RGB2Y{ 0.272229f, 0.674082f, 0.0536895f };
|
||||
@@ -233,7 +191,7 @@ inline float3 ACES(float3 color) {
|
||||
linearCV = mix(float3(dot(linearCV, AP1_RGB2Y)), linearCV, ODT_SAT_FACTOR);
|
||||
|
||||
// Convert to display primary encoding (Rec.709 primaries, D65 white point)
|
||||
return AP1_2_sRGB * linearCV;
|
||||
return AP1_to_sRGB * linearCV;
|
||||
}
|
||||
|
||||
} // namespace aces
|
||||
|
||||
@@ -578,6 +578,9 @@ static void gui(filament::Engine* engine, filament::View*) {
|
||||
"Linear\0ACES\0Filmic\0Reinhard\0Display Range\0\0");
|
||||
ImGui::SliderInt("Temperature", ¶ms.colorGradingOptions.temperature, -100, 100);
|
||||
ImGui::SliderInt("Tint", ¶ms.colorGradingOptions.tint, -100, 100);
|
||||
ImGui::SliderFloat3("Out Red", ¶ms.colorGradingOptions.outRed.x, -2.0f, 2.0f);
|
||||
ImGui::SliderFloat3("Out Green", ¶ms.colorGradingOptions.outGreen.x, -2.0f, 2.0f);
|
||||
ImGui::SliderFloat3("Out Blue", ¶ms.colorGradingOptions.outBlue.x, -2.0f, 2.0f);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Debug")) {
|
||||
@@ -694,8 +697,9 @@ static void preRender(filament::Engine* engine, filament::View* view, filament::
|
||||
if (memcmp(&g_params.colorGradingOptions, &g_lastColorGradingOptions, sizeof(ColorGradingOptions))) {
|
||||
ColorGradingOptions& options = g_params.colorGradingOptions;
|
||||
ColorGrading* colorGrading = ColorGrading::Builder()
|
||||
.toneMapping(options.toneMapping)
|
||||
.whiteBalance(options.temperature / 100.0f, options.tint / 100.0f)
|
||||
.channelMixer(options.outRed, options.outGreen, options.outBlue)
|
||||
.toneMapping(options.toneMapping)
|
||||
.build(*engine);
|
||||
view->setColorGrading(colorGrading);
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ struct ColorGradingOptions {
|
||||
ColorGrading::ToneMapping toneMapping = ColorGrading::ToneMapping::ACES;
|
||||
int temperature = 0;
|
||||
int tint = 0;
|
||||
math::float3 outRed{1.0f, 0.0f, 0.0f};
|
||||
math::float3 outGreen{0.0f, 1.0f, 0.0f};
|
||||
math::float3 outBlue{0.0f, 0.0f, 1.0f};
|
||||
};
|
||||
|
||||
struct SandboxParameters {
|
||||
|
||||
Reference in New Issue
Block a user