From 451ae01617fa8a9deba9328fb87bf9e26de69213 Mon Sep 17 00:00:00 2001 From: Andrew Kensler Date: Wed, 10 Jul 2024 22:27:15 -0700 Subject: [PATCH] Add tonemapper that hashes to a random color --- include/tev/Common.h | 1 + src/Common.cpp | 2 ++ src/ImageCanvas.cpp | 11 +++++++++++ src/ImageViewer.cpp | 10 +++++++--- src/UberShader.cpp | 23 ++++++++++++++++++++++- src/main.cpp | 1 + 6 files changed, 44 insertions(+), 4 deletions(-) diff --git a/include/tev/Common.h b/include/tev/Common.h index f6a3837a..62c352bd 100644 --- a/include/tev/Common.h +++ b/include/tev/Common.h @@ -373,6 +373,7 @@ enum ETonemap : int { Gamma, FalseColor, PositiveNegative, + Hash, // This enum value should never be used directly. // It facilitates looping over all members of this enum. diff --git a/src/Common.cpp b/src/Common.cpp index 42b5eb27..84cff390 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -232,6 +232,8 @@ ETonemap toTonemap(string name) { return FalseColor; } else if (name == "POSITIVENEGATIVE" || name == "POSNEG" || name == "PN" ||name == "+-") { return PositiveNegative; + } else if (name == "HASH") { + return Hash; } else { return SRGB; } diff --git a/src/ImageCanvas.cpp b/src/ImageCanvas.cpp index c3358808..8be67ef2 100644 --- a/src/ImageCanvas.cpp +++ b/src/ImageCanvas.cpp @@ -558,6 +558,17 @@ Vector3f ImageCanvas::applyTonemap(const Vector3f& value, float gamma, ETonemap result = {-2.0f * mean(min(value, Vector3f{0.0f})), 2.0f * mean(max(value, Vector3f{0.0f})), 0.0f}; break; } + case ETonemap::Hash: + { + static const auto fract = [](float x){ return x - floor(x); }; + result = value; + result *= {abs(result.x()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.y()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.z()) < 1024.0f ? 1.0f : 1.0f / 1024.0f}; + result *= {abs(result.x()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.y()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.z()) < 1024.0f ? 1.0f : 1.0f / 1024.0f}; + result *= {abs(result.x()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.y()) < 1024.0f ? 1.0f : 1.0f / 1024.0f, abs(result.z()) < 1024.0f ? 1.0f : 1.0f / 1024.0f}; + result = abs(fract(dot(result, Vector3f{115.191742f, 64.0546951f, 124.512291f})) - 0.5f) * Vector3f{1368.46143f, 1523.2019f, 1034.50476f}; + result = {2.0f * abs(fract(result.x()) - 0.5f), 2.0f * abs(fract(result.y()) - 0.5f), 2.0f * abs(fract(result.z()) - 0.5f)}; + break; + } default: throw runtime_error{"Invalid tonemap selected."}; } diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index 3871d267..2be60420 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -25,7 +25,7 @@ using namespace std; namespace tev { -static const int SIDEBAR_MIN_WIDTH = 230; +static const int SIDEBAR_MIN_WIDTH = 245; static const float CROP_MIN_SIZE = 3; ImageViewer::ImageViewer( @@ -214,7 +214,7 @@ ImageViewer::ImageViewer( // Tonemap options { mTonemapButtonContainer = new Widget{mSidebarLayout}; - mTonemapButtonContainer->set_layout(new GridLayout{Orientation::Horizontal, 4, Alignment::Fill, 5, 2}); + mTonemapButtonContainer->set_layout(new GridLayout{Orientation::Horizontal, 5, Alignment::Fill, 5, 2}); auto makeTonemapButton = [&](const string& name, function callback) { auto button = new Button{mTonemapButtonContainer, name}; @@ -228,6 +228,7 @@ ImageViewer::ImageViewer( makeTonemapButton("Gamma", [this]() { setTonemap(ETonemap::Gamma); }); makeTonemapButton("FC", [this]() { setTonemap(ETonemap::FalseColor); }); makeTonemapButton("+/-", [this]() { setTonemap(ETonemap::PositiveNegative); }); + makeTonemapButton("Hash", [this]() { setTonemap(ETonemap::Hash); }); setTonemap(ETonemap::SRGB); @@ -244,7 +245,10 @@ ImageViewer::ImageViewer( "False-color visualization\n\n" "+/-\n" - "Positive=Green, Negative=Red" + "Positive=Green, Negative=Red\n\n" + + "Hash\n" + "Hash values to random colors" ); } diff --git a/src/UberShader.cpp b/src/UberShader.cpp index 6a1167dd..c8b36cac 100644 --- a/src/UberShader.cpp +++ b/src/UberShader.cpp @@ -18,7 +18,8 @@ UberShader::UberShader(RenderPass* renderPass) { # elif defined(NANOGUI_USE_GLES) std::string preamble = R"(#version 100 - precision highp float;)"; + precision highp float; + precision highp sampler2D;)"; # endif auto vertexShader = preamble + R"glsl( @@ -51,6 +52,7 @@ UberShader::UberShader(RenderPass* renderPass) { #define GAMMA 1 #define FALSE_COLOR 2 #define POS_NEG 3 + #define HASH 4 #define ERROR 0 #define ABSOLUTE_ERROR 1 @@ -117,6 +119,13 @@ UberShader::UberShader(RenderPass* renderPass) { } } + vec3 hash(vec3 co){ + co *= mix(vec3(1.0), vec3(1.0 / 1024.0), step(1024.0, abs(co))); + co *= mix(vec3(1.0), vec3(1.0 / 1024.0), step(1024.0, abs(co))); + co *= mix(vec3(1.0), vec3(1.0 / 1024.0), step(1024.0, abs(co))); + return 2.0 * abs(fract(abs(fract(dot(co, vec3(115.191742, 64.0546951, 124.512291))) - 0.5) * vec3(1368.46143, 1523.2019, 1034.50476)) - 0.5); + } + vec3 applyTonemap(vec3 col, vec4 background) { if (tonemap == SRGB) { col = col + @@ -129,6 +138,8 @@ UberShader::UberShader(RenderPass* renderPass) { return falseColor(log2(average(col)+0.03125) / 10.0 + 0.5) + (background.rgb - falseColor(0.0)) * background.a; } else if (tonemap == POS_NEG) { return vec3(-average(min(col, vec3(0.0))) * 2.0, average(max(col, vec3(0.0))) * 2.0, 0.0) + background.rgb * background.a; + } else if (tonemap == HASH) { + return hash(col) + (background.rgb - hash(vec3(offset))) * background.a; } return vec3(0.0); } @@ -230,6 +241,7 @@ UberShader::UberShader(RenderPass* renderPass) { #define GAMMA 1 #define FALSE_COLOR 2 #define POS_NEG 3 + #define HASH 4 #define ERROR 0 #define ABSOLUTE_ERROR 1 @@ -272,6 +284,13 @@ UberShader::UberShader(RenderPass* renderPass) { } } + float3 hash(float3 co){ + co *= mix(float3(1.0f), float3(1.0f / 1024.0f), step(1024.0f, abs(co))); + co *= mix(float3(1.0f), float3(1.0f / 1024.0f), step(1024.0f, abs(co))); + co *= mix(float3(1.0f), float3(1.0f / 1024.0f), step(1024.0f, abs(co))); + return 2.0f * abs(fract(abs(fract(dot(co.xyz, float3(115.191742f, 64.0546951f, 124.512291f))) - 0.5f) * float3(1368.46143f, 1523.2019f, 1034.50476f)) - 0.5f); + } + float3 applyTonemap(float3 col, float4 background, int tonemap, float offset, float gamma, texture2d colormap, sampler colormapSampler) { switch (tonemap) { case SRGB: @@ -286,6 +305,8 @@ UberShader::UberShader(RenderPass* renderPass) { return falseColor(log2(average(col)+0.03125f) / 10.0f + 0.5f, colormap, colormapSampler) + (background.rgb - falseColor(0.0f, colormap, colormapSampler)) * background.a; case POS_NEG: return float3(-average(min(col, float3(0.0f))) * 2.0f, average(max(col, float3(0.0f))) * 2.0f, 0.0f) + background.rgb * background.a; + case HASH: + return hash(col) + (background.rgb - hash(float3(offset))) * background.a; } return float3(0.0f); } diff --git a/src/main.cpp b/src/main.cpp index 10d044aa..40bd72b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -233,6 +233,7 @@ int mainFunc(const vector& arguments) { "Gamma - Gamma curve\n" "FC - False Color\n" "PN - Positive=Green, Negative=Red\n" + "Hash - Hash values to random colors\n" "Default is sRGB.", {'t', "tonemap"}, };