|
| 1 | +/* Constant node for deep nodes with adjustable samples and depth range. |
| 2 | +
|
| 3 | +Falk Hofmann, 11/2021 |
| 4 | +*/ |
| 5 | + |
| 6 | +#include "DDImage/Iop.h" |
| 7 | +#include "DDImage/DeepFilterOp.h" |
| 8 | +#include "DDImage/Knobs.h" |
| 9 | + |
| 10 | +static const char* CLASS = "DeepCConstant"; |
| 11 | +static const char* const enumAlphaTypes[] = { "unform", "additive", "multiplicative", 0 }; |
| 12 | +using namespace DD::Image; |
| 13 | + |
| 14 | +class DeepCConstant : public DeepFilterOp |
| 15 | +{ |
| 16 | + FormatPair formats; |
| 17 | + ChannelSet channels; |
| 18 | + float color[4]; |
| 19 | + double _front; |
| 20 | + double _back; |
| 21 | + int _samples; |
| 22 | + float _overallDepth; |
| 23 | + float _sampleDistance; |
| 24 | + double _values[4]; |
| 25 | + int _alphaType; |
| 26 | + float _modAlpha; |
| 27 | + |
| 28 | +public: |
| 29 | + |
| 30 | + int minimum_inputs() const { return 0;} |
| 31 | + |
| 32 | + DeepCConstant(Node* node) : DeepFilterOp(node) { |
| 33 | + |
| 34 | + formats.format(nullptr); |
| 35 | + _front = 0; |
| 36 | + _back = 10; |
| 37 | + _samples = 1; |
| 38 | + _overallDepth = 1; |
| 39 | + _sampleDistance = 0.1f; |
| 40 | + color[0] = color[1] = color[2] = color[3] = 0.5; |
| 41 | + channels = Mask_RGBA; |
| 42 | + _alphaType = 2; |
| 43 | + _values[0] = _values[1] = _values[2] = _values[3] = 0.5; |
| 44 | + _modAlpha = 1.0; |
| 45 | + } |
| 46 | + void _validate(bool); |
| 47 | + bool doDeepEngine(DD::Image::Box bbox, const DD::Image::ChannelSet& requestedChannels, DeepOutputPlane& deepOutPlane); |
| 48 | + void knobs(Knob_Callback); |
| 49 | + int knob_changed(Knob* k); |
| 50 | + |
| 51 | + void calcValues(); |
| 52 | + |
| 53 | + static const Iop::Description d; |
| 54 | + const char* Class() const { return d.name;} |
| 55 | + const char* node_help() const; |
| 56 | + virtual Op* op() { return this; } |
| 57 | +}; |
| 58 | + |
| 59 | + const char* DeepCConstant::node_help() const |
| 60 | + {return "A DeepConstant with defined deep range and amount of samples.\n\n" |
| 61 | + "Falk Hofmann 11/2021";} |
| 62 | + |
| 63 | + void DeepCConstant::knobs(Knob_Callback f) |
| 64 | + { |
| 65 | + Input_ChannelSet_knob(f, &channels, 4, "channels"); |
| 66 | + AColor_knob(f, color, "color", "color"); |
| 67 | + Format_knob(f, &formats, "format", "format"); |
| 68 | + Obsolete_knob(f, "full_format", "knob format $value"); |
| 69 | + Obsolete_knob(f, "proxy_format", nullptr); |
| 70 | + Divider(f, ""); |
| 71 | + Enumeration_knob(f, &_alphaType, enumAlphaTypes, "alpha_mode", "split alpha mode"); |
| 72 | + Tooltip(f, "Select the alpha mode.\n\n" |
| 73 | + "multiplactive will match the image visually as compared to a 2d constant.\n\n" |
| 74 | + "additive does a straight division by the number of samples and therefore will not match the 2d equivalent.\n\n" |
| 75 | + "uniform applies the given color values straight to the samples, without considering and modifications due deep sample addition." ); |
| 76 | + Double_knob(f, &_front, "front", "front"); |
| 77 | + Tooltip(f, "Closest distance from camera."); |
| 78 | + Double_knob(f, &_back, "back", "back"); |
| 79 | + Tooltip(f, "Farthest distance from camera."); |
| 80 | + Int_knob(f, &_samples, "samples", "samples"); |
| 81 | + Tooltip(f, "Amount of deep samples per pixel."); |
| 82 | + SetRange(f, 2, 1000); |
| 83 | + SetFlags(f, Knob::NO_ANIMATION); |
| 84 | + |
| 85 | + } |
| 86 | + |
| 87 | + void DeepCConstant::calcValues(){ |
| 88 | + |
| 89 | + float a = knob("color")->get_value(colourIndex(Chan_Alpha)); |
| 90 | + int saveSample = (_samples > 0)? _samples: 1; |
| 91 | + _modAlpha = 1.0f- pow(1.0f - a, (1.0f/saveSample)); |
| 92 | + |
| 93 | + |
| 94 | + for (int c = 0; c < 4; c++){ |
| 95 | + |
| 96 | + float val = knob("color")->get_value(c); |
| 97 | + switch (_alphaType) |
| 98 | + { |
| 99 | + case 0: |
| 100 | + _values[c] = val; |
| 101 | + break; |
| 102 | + case 1: |
| 103 | + _values[c] = val/saveSample; |
| 104 | + break; |
| 105 | + case 2: |
| 106 | + _values[c] = (val/a) * _modAlpha; |
| 107 | + } |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + |
| 112 | + int DeepCConstant::knob_changed(Knob* k){ |
| 113 | + if (k->name() == "alpha_mode"){ |
| 114 | + DeepCConstant::calcValues(); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + void DeepCConstant::_validate(bool for_real) |
| 119 | + { |
| 120 | + ChannelSet new_channelset; |
| 121 | + new_channelset += Mask_Deep; |
| 122 | + new_channelset += Mask_Z; |
| 123 | + new_channelset += Mask_Alpha; |
| 124 | + new_channelset += channels; |
| 125 | + |
| 126 | + Box box(0, 0, formats.format()->width(), formats.format()->height()) ; |
| 127 | + _deepInfo = DeepInfo(formats, box, new_channelset); |
| 128 | + _overallDepth = _back - _front; |
| 129 | + _sampleDistance = _overallDepth/(_samples); |
| 130 | + DeepCConstant::calcValues(); |
| 131 | + } |
| 132 | + |
| 133 | + bool DeepCConstant::doDeepEngine(DD::Image::Box box, const DD::Image::ChannelSet& channels, DeepOutputPlane& plane) |
| 134 | + { |
| 135 | + int saveSample = (_samples > 0) ? _samples: 1; |
| 136 | + |
| 137 | + DeepInPlaceOutputPlane outPlane(channels, box, DeepPixel::eZDescending); |
| 138 | + outPlane.reserveSamples(box.area()); |
| 139 | + |
| 140 | + for (Box::iterator it = box.begin(); |
| 141 | + it != box.end(); |
| 142 | + it++) { |
| 143 | + |
| 144 | + outPlane.setSampleCount(it, saveSample); |
| 145 | + DeepOutputPixel out = outPlane.getPixel(it); |
| 146 | + for (int sampleNo = 0; sampleNo < saveSample; sampleNo++){ |
| 147 | + |
| 148 | + foreach (z, channels) { |
| 149 | + float& output = out.getWritableOrderedSample(sampleNo, z); |
| 150 | + int cIndex = colourIndex(z); |
| 151 | + |
| 152 | + if (z == Chan_DeepFront){ |
| 153 | + output = _front + (_sampleDistance * sampleNo); |
| 154 | + |
| 155 | + } |
| 156 | + else if (z == Chan_DeepBack){ |
| 157 | + output = _front + (_sampleDistance * sampleNo) + _sampleDistance; |
| 158 | + |
| 159 | + } |
| 160 | + else{ |
| 161 | + output = _values[cIndex]; |
| 162 | + } |
| 163 | + } |
| 164 | + } |
| 165 | + } |
| 166 | + mFnAssert(outPlane.isComplete()); |
| 167 | + plane = outPlane; |
| 168 | + |
| 169 | + |
| 170 | + return true; |
| 171 | +} |
| 172 | + |
| 173 | +static Op* build(Node* node) { return new DeepCConstant(node); } |
| 174 | +const Op::Description DeepCConstant::d("DeepCConstant", 0, build); |
0 commit comments