Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ session_manager.mu
# See maya_tools.mu.in
maya_tools.mu
# See rvnuke_mode.mu.in
rvnuke_mode.mu
rvnuke_mode.musrc/plugins/rv-packages/session_manager/composite_ui.py
*_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ The stack node is part of a stack group and handles control for settings like co
| output.size | int[2] | 1 | The virtual output size of the stack. This may not match the input sizes. |
| output.autoSize | int | 1 | Figure out a good size automatically from the input sizes if 1. Otherwise use output.size. |
| output.chosenAudioInput | string | 1 | Name of input which becomes the audio output of the stack. If the value is .all. then all inputs are mixed. If the value is .first. then the first input is used. |
| composite.type | string | 1 | The compositing operation to perform on the inputs. Valid values are: over, add, difference, -difference, and replace |
| composite.type | string | 1 | The compositing operation to perform on the inputs. Valid values are: over, add, dissolve, difference, -difference, replace, and topmost |
| mode.useCutInfo | int | 1 | Use cut information on the inputs to determine EDL timing. |
| mode.strictFrameRanges | int | 1 | If 1 match the timeline frames to the source frames instead of retiming to frame 1. |
| mode.alignStartFrames | int | 1 | If 1 offset all inputs so they start at same frame as the first input. |
Expand Down
3 changes: 3 additions & 0 deletions src/lib/ip/IPBaseNodes/IPBaseNodes/StackIPNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ namespace IPCore

IntProperty* autoSizeProperty() const { return m_autoSize; }

// float dissolveAmount() const { return m_dissolveAmount->front(); }

virtual void propagateFlushToInputs(const FlushContext&);

void invalidate();
Expand Down Expand Up @@ -112,6 +114,7 @@ namespace IPCore
IntProperty* m_autoSize;
IntProperty* m_interactiveSize;
IntProperty* m_supportReversedOrderBlending;
FloatProperty* m_dissolveAmount;

private:
static std::string m_defaultCompType;
Expand Down
33 changes: 31 additions & 2 deletions src/lib/ip/IPBaseNodes/StackIPNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ namespace IPCore
|| this->name() == "defaultLayout_stack")
? m_defaultCompType
: "over");

m_dissolveAmount = declareProperty<FloatProperty>("composite.dissolveAmount", 0.5f);
}

StackIPNode::~StackIPNode() { pthread_mutex_destroy(&m_lock); }
Expand Down Expand Up @@ -175,6 +177,9 @@ namespace IPCore

if (p == m_activeAudioInput)
updateChosenAudioInput();

if (p == m_dissolveAmount)
invalidate();
}

IPNode::propertyChanged(p);
Expand Down Expand Up @@ -453,7 +458,16 @@ namespace IPCore
inExpressions);

root->appendChildren(images);
root->mergeExpr = newBlend(root, inExpressions, mode);
if (mode == IPImage::Dissolve)
{
float dissolveAmount = m_dissolveAmount ? m_dissolveAmount->front() : 0.5f;
root->mergeExpr = newDissolveBlend(root, inExpressions, mode, dissolveAmount);
}
else
{
root->mergeExpr = newBlend(root, inExpressions, mode);
}

root->shaderExpr = Shader::newSourceRGBA(root);
root->recordResourceUsage();

Expand Down Expand Up @@ -504,10 +518,12 @@ namespace IPCore
const IPImage::BlendMode mode = IPImage::getBlendModeFromString(comp);

const bool topmostOnly = !strcmp(comp, "topmost");
const bool dissolveOnly = !strcmp(comp, "dissolve");

const bool localUseMerge =
useMerge
|| (mode == IPImage::Replace && !topmostOnly && useMergeForReplace);
|| (mode == IPImage::Replace && !topmostOnly && useMergeForReplace)
|| (mode == IPImage::Dissolve);

IPImage* root = 0;

Expand Down Expand Up @@ -568,6 +584,12 @@ namespace IPCore
haveOneImage = true;
}

if (dissolveOnly && images.size() >= 2)
{
// For dissolve mode, only process the first two inputs
break;
}

Context c = context;
c.fps = m_outputFPS->front();
c.frame = inputFrame(i, frame);
Expand Down Expand Up @@ -726,6 +748,7 @@ namespace IPCore
}

const bool topmostOnly = (!strcmp(comp, "topmost"));
const bool dissolveOnly = (!strcmp(comp, "dissolve"));
const bool strictFrameRanges = m_strictFrameRanges->front();
const bool useCutInfo = m_useCutInfo->front();

Expand Down Expand Up @@ -764,6 +787,12 @@ namespace IPCore
haveOneImage = true;
}

if (dissolveOnly && i >= 2)
{
// For dissolve mode, only process the first two inputs
break;
}

Context c = context;
c.frame = inputFrame(i, frame);

Expand Down
1 change: 1 addition & 0 deletions src/lib/ip/IPCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ SET(_shaders
ReverseDifference2
ReverseDifference3
ReverseDifference4
Dissolve2
InlineDissolve2
ColorCDL_SAT_noClamp
ColorPremultLight
Expand Down
3 changes: 3 additions & 0 deletions src/lib/ip/IPCore/IPCore/ShaderCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ namespace IPCore
Expression* newBlend(const IPImage*, const std::vector<Expression*>&,
const IPImage::BlendMode);

Expression* newDissolveBlend(const IPImage*, const std::vector<Expression*>&,
const IPImage::BlendMode, float dissolveAmount);

Expression* newHistogram(const IPImage*,
const std::vector<Expression*>&);

Expand Down
1 change: 0 additions & 1 deletion src/lib/ip/IPCore/IPImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ namespace IPCore
blendMode = IPImage::Replace;
else if (!strcmp(blendModeString, "topmost"))
blendMode = IPImage::Replace;

return blendMode;
}

Expand Down
59 changes: 58 additions & 1 deletion src/lib/ip/IPCore/ShaderCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <IPCore/ShaderFunction.h>
#include <IPCore/ShaderSymbol.h>
#include <IPCore/IPImage.h>
#include <IPBaseNodes/StackIPNode.h>
#include <TwkGLF/GL.h>
#include <TwkFB/Operations.h>
#include <TwkMath/MatrixColor.h>
Expand Down Expand Up @@ -142,6 +143,7 @@ extern const char* Difference4_glsl;
extern const char* ReverseDifference2_glsl;
extern const char* ReverseDifference3_glsl;
extern const char* ReverseDifference4_glsl;
extern const char* Dissolve2_glsl;
extern const char* InlineDissolve2_glsl;
extern const char* BoxFilter_glsl;
extern const char* ConstantBG_glsl;
Expand Down Expand Up @@ -844,6 +846,30 @@ namespace IPCore
funcName, shaderCode, Shader::Function::Color, params, globals);
}

Function* dissolveBlend(int no, const char* funcName, const char* shaderCode)
{
assert(no >= 2);
assert(no <= MAX_TEXTURE_PER_SHADER);

SymbolVector params, globals;

// Add input texture parameters (i0, i1, i2, i3)
for (int i = 0; i < no; ++i)
{
ostringstream str;
str << "i" << i;
params.push_back(new Symbol(Symbol::ParameterConstIn, str.str(),
Symbol::Vec4fType));
}

// Add dissolve amount parameter
params.push_back(new Symbol(Symbol::ParameterConstIn, "dissolveAmount",
Symbol::FloatType));

return new Shader::Function(
funcName, shaderCode, Shader::Function::Color, params, globals);
}

Function* colorQuantize()
{
if (!Shader_ColorQuantize)
Expand Down Expand Up @@ -3036,6 +3062,7 @@ namespace IPCore
const char* reverseDifferenceShaders[] = {ReverseDifference2_glsl,
ReverseDifference3_glsl,
ReverseDifference4_glsl};
const char* dissolveShaders[] = {Dissolve2_glsl};

// generate a blend expr of a certain mode
// with the input Expressions as input to the blend shaders (over, add,
Expand Down Expand Up @@ -3080,7 +3107,6 @@ namespace IPCore
F = blend(size, name,
overShaders[size - 2]); //*2_glsl is at position 0
break;
// TODO: dissolve
}

ArgumentVector args(F->parameters().size());
Expand All @@ -3093,6 +3119,37 @@ namespace IPCore
return new Expression(F, args, image);
}

// Dissolve blend function for exactly 2 inputs with dissolveAmount parameter
Expression* newDissolveBlend(const IPImage* image,
const vector<Expression*>& FA1,
const IPImage::BlendMode mode,
float dissolveAmount)
{
if (mode == IPImage::Dissolve)
{
int size = FA1.size();
assert(size == 2); // Dissolve only works with exactly 2 inputs

// Create dissolve blend function for 2 inputs
Function* F = dissolveBlend(2, "main", dissolveShaders[0]);
ArgumentVector args(F->parameters().size());

// Bind the 2 input expressions
args[0] = new BoundExpression(F->parameters()[0], FA1[0]);
args[1] = new BoundExpression(F->parameters()[1], FA1[1]);

// Bind the dissolveAmount parameter
args[2] = new BoundFloat(F->parameters()[2], dissolveAmount);

return new Expression(F, args, image);
}
else
{
// For non-dissolve modes, use the original function
return newBlend(image, FA1, mode);
}
}

Expression* newHistogram(const IPImage* image,
const std::vector<Expression*>& FA1)
{
Expand Down
20 changes: 20 additions & 0 deletions src/lib/ip/IPCore/glsl/Dissolve2.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Copyright (C) 2023 Autodesk, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
// Dissolve blend between two inputs with configurable amount

vec4 main(const in vec4 i0, const in vec4 i1, const in float dissolveAmount)
{
// Blend RGB channels using dissolveAmount (0.0 = all i1, 1.0 = all i0)
vec3 rgb = mix(i1.rgb, i0.rgb, dissolveAmount);

// Ignore input alpha channels and output solid alpha of 1.0
float alpha = 1.0;

return vec4(clamp(rgb.r, 0.0, 1.0),
clamp(rgb.g, 0.0, 1.0),
clamp(rgb.b, 0.0, 1.0),
alpha);
}
Loading
Loading