From 4d2f8f775c404ff3733f91cf21f52a6710239527 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 24 Apr 2022 18:50:06 +0100 Subject: [PATCH] Add ability to add custom shaders to ColorProcessorJobs --- app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/node/keying/CMakeLists.txt | 1 + app/node/keying/chromakey/CMakeLists.txt | 22 ++++++ app/node/keying/chromakey/chromakey.cpp | 89 ++++++++++++++++++++++++ app/node/keying/chromakey/chromakey.h | 53 ++++++++++++++ app/render/job/colortransformjob.h | 7 ++ app/render/renderer.cpp | 26 ++++--- app/render/renderer.h | 5 +- app/render/renderprocessor.cpp | 2 +- app/shaders/chromakey.frag | 34 +++++++++ 11 files changed, 232 insertions(+), 11 deletions(-) create mode 100644 app/node/keying/chromakey/CMakeLists.txt create mode 100644 app/node/keying/chromakey/chromakey.cpp create mode 100644 app/node/keying/chromakey/chromakey.h create mode 100644 app/shaders/chromakey.frag diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 02af0aded..0958d2d92 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -54,6 +54,7 @@ #include "math/trigonometry/trigonometry.h" #include "keying/colordifferencekey/colordifferencekey.h" #include "keying/despill/despill.h" +#include "keying/chromakey/chromakey.h" #include "output/track/track.h" #include "output/viewer/viewer.h" #include "project/folder/folder.h" @@ -283,6 +284,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new DisplayTransformNode(); case kOCIOGradingTransform: return new OCIOGradingTransformNode(); + case kChromaKey: + return new ChromaKeyNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index b57cdfe40..42658cfb2 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -72,6 +72,7 @@ public: kCornerPinDistort, kDisplayTransform, kOCIOGradingTransform, + kChromaKey, // Count value kInternalNodeCount diff --git a/app/node/keying/CMakeLists.txt b/app/node/keying/CMakeLists.txt index 2177a550a..4dbd437cd 100644 --- a/app/node/keying/CMakeLists.txt +++ b/app/node/keying/CMakeLists.txt @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(chromakey) add_subdirectory(colordifferencekey) add_subdirectory(despill) diff --git a/app/node/keying/chromakey/CMakeLists.txt b/app/node/keying/chromakey/CMakeLists.txt new file mode 100644 index 000000000..c2af2bba4 --- /dev/null +++ b/app/node/keying/chromakey/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/keying/chromakey/chromakey.h + node/keying/chromakey/chromakey.cpp + PARENT_SCOPE +) \ No newline at end of file diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp new file mode 100644 index 000000000..b57781fbc --- /dev/null +++ b/app/node/keying/chromakey/chromakey.cpp @@ -0,0 +1,89 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#include "chromakey.h" + +#include "node/color/colormanager/colormanager.h" +#include "render/colorprocessor.h" + +namespace olive { + +#define super OCIOBaseNode + +ChromaKeyNode::ChromaKeyNode() +{ +} + +QString ChromaKeyNode::Name() const +{ + return tr("Chroma Key"); +} + +QString ChromaKeyNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.chromakey"); +} + +QVector ChromaKeyNode::Category() const +{ + return {kCategoryKeying}; +} + +QString ChromaKeyNode::Description() const +{ + return tr("A simple color key based on the distance from the chroma of a selected color."); +} + +void ChromaKeyNode::Retranslate() +{ + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); + //SetInputName(kGarbageMatteInput, tr("Garbage Matte")); + //SetInputName(kCoreMatteInput, tr("Core Matte")); + //SetInputName(kColorInput, tr("Key Color")); + //SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")}); + //SetInputName(kShadowsInput, tr("Shadows")); + //SetInputName(kHighlightsInput, tr("Highlights")); + //SetInputName(kMaskOnlyInput, tr("Show Mask Only")); +} + +void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element); + GenerateProcessor(); +} + +void ChromaKeyNode::GenerateProcessor() +{ + if (manager()){ + ColorTransform transform("cie_xyz_d65_interchange"); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + } +} + +void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + if (!value[kTextureInput].data().isNull() && processor()) { + ColorTransformJob job; + + job.SetColorProcessor(processor()); + job.SetInputTexture(value[kTextureInput].data().value()); + job.SetShaderPath(QStringLiteral(":/shaders/chromakey.frag")); + + table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + } +} + +} // namespace olive \ No newline at end of file diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h new file mode 100644 index 000000000..c14272e02 --- /dev/null +++ b/app/node/keying/chromakey/chromakey.h @@ -0,0 +1,53 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#ifndef CHROMAKEYNODE_H +#define CHROMAKEYNODE_H + +#include "node/color/ociobase/ociobase.h" + +namespace olive { + +class ChromaKeyNode : public OCIOBaseNode { + Q_OBJECT + public: + ChromaKeyNode(); + + NODE_DEFAULT_DESTRUCTOR(ChromaKeyNode) + NODE_COPY_FUNCTION(ChromaKeyNode) + + virtual QString Name() const override; + virtual QString id() const override; + virtual QVector Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + + virtual void InputValueChangedEvent(const QString& input, int element) override; + + virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; + + virtual void ConfigChanged() override {}; + +private: + void GenerateProcessor(); + + + +}; + +} // namespace olive + +#endif // CHROMAKEYNODE_H diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index cf653d27e..3bed475f8 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -21,6 +21,8 @@ #ifndef COLORTRANSFORMJOB_H #define COLORTRANSFORMJOB_H +#include + #include "render/colorprocessor.h" #include "render/texture.h" @@ -40,11 +42,16 @@ public: ColorProcessorPtr GetColorProcessor() const { return processor_; } void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } + QString GetShaderPath() const { return shader_path_; } + void SetShaderPath(const QString shader_path) { shader_path_ = shader_path; } + private: ColorProcessorPtr processor_; TexturePtr input_texture_; + QString shader_path_; + }; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index b78df3df4..6adab6348 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -57,6 +57,11 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix); } +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) +{ + BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix, shader_path); +} + void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) { BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); @@ -103,7 +108,7 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) +bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx, QString shader_path) { QMutexLocker locker(&color_cache_mutex_); @@ -123,11 +128,16 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo // Generate shader color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")).arg( - shader_desc->getShaderText(), - ocio_func_name - ); + QString shader_frag; + if (shader_path.isEmpty()) { + // Generate shader code using OCIO stub and our auto-generated name + shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")) + .arg(shader_desc->getShaderText(), ocio_func_name); + } else { + // FIXME: Currently only supports a single function + shader_frag = FileFunctions::ReadFileAsString(shader_path) + .arg(shader_desc->getShaderText(), ocio_func_name); + } // Try to compile shader color_ctx.compiled_shader = CreateNativeShader(ShaderCode(shader_frag, @@ -208,10 +218,10 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture *destination, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, - const QMatrix4x4& crop_matrix) + const QMatrix4x4& crop_matrix, const QString shader_path) { ColorContext color_ctx; - if (!GetColorContext(color_processor, &color_ctx)) { + if (!GetColorContext(color_processor, &color_ctx, shader_path)) { return; } diff --git a/app/render/renderer.h b/app/render/renderer.h index 977fc98ce..58e306c4b 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -70,6 +70,7 @@ public: }; void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms); @@ -126,12 +127,12 @@ private: }; - bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); + bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, const QString shader_path); void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, VideoParams params, bool clear_destination, - const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix); + const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix, const QString shader_path = QString()); QHash color_cache_; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index f223824cb..55963a965 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -571,7 +571,7 @@ TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorT TexturePtr src = job.GetInputTexture(); TexturePtr dest = render_ctx_->CreateTexture(src->params()); - render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get()); + render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get(), job.GetShaderPath()); return dest; } diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag new file mode 100644 index 000000000..b4b35e524 --- /dev/null +++ b/app/shaders/chromakey.frag @@ -0,0 +1,34 @@ +uniform sampler2D tex_in; +in vec2 ove_texcoord; +out vec4 frag_color; + +// OCIO shader code +%1 + +// Assume D65 white point +float Xn = 95.0489; +float Yn = 100.0; +float Zn = 108.8840; +float delta = 0.20689655172; // 6/29 + +float func(float t) { + if (t > pow(delta, 3.0)){ + return pow(t, 1.0/3.0); + } else{ + return (t / (3.0 * pow(delta, 2))) + 4.0/29.0; + } +} + +void main() { + vec4 col = texture2D(tex_in, ove_texcoord); + vec4 new_col; + + new_col = %2(col); + + vec4 lab; + lab.r = 116.0 * func(col.g / Yn) - 16.0; + lab.g = 500.0 * (func(col.r / Xn) - func(col.g / Yn)); + lab.b = 200.0 * (func(col.g / Yn) - func(col.b / Zn)); + lab.w = 1.0; + frag_color = col; +}