#include "DDImage/Iop.h" #include "DDImage/Row.h" #include "DDImage/DeepOp.h" #include "DDImage/Knobs.h" #include "DDImage/Pixel.h" #include "DDImage/DeepComposite.h" const char* CLASS = "DeepToImage"; using namespace DD::Image; class DeepToImage : public DD::Image::Iop { bool _volumetricComposition; public: DeepToImage(Node* node) : Iop(node) { _volumetricComposition = true; } Op* default_input(int idx) const override { return nullptr; } int minimum_inputs() const override { return 1; } int maximum_inputs() const override { return 1; } bool test_input(int idx, Op*op) const override { return dynamic_cast(op); } DeepOp* input0() { return dynamic_cast(Op::input(0)); } const char* node_help() const override { return "Composites deep data to a 2D image."; } const char* Class() const override { return CLASS; } const char* node_shape() const override { return DeepOp::DeepNodeShape(); } void knobs(Knob_Callback f) override { Bool_knob(f, &_volumetricComposition, "volumetric_composition", "volumetric composition"); Tooltip(f, "With this selected, Nuke will take into account the back depth of samples for compositing into 2D, rather than only using the front depth and assuming samples do not overlap."); } void _validate(bool r) override { if (input0()) { input0()->validate(true); DeepInfo deepInfo = input0()->deepInfo(); DD::Image::Box realBox = deepInfo.box(); info_.setFormats(deepInfo.formats()); info_.set(realBox); info_.channels(deepInfo.channels() + Mask_Z); info_.first_frame(deepInfo.firstFrame()); info_.last_frame(deepInfo.lastFrame()); set_out_channels(deepInfo.channels() + Mask_Z); input0()->op()->cached(cached()); } else { info_.set(DD::Image::Box()); info_.channels(Mask_None); } } void getNeededChannels(ChannelSet& channels) const { if (_volumetricComposition || channels.contains(Chan_Z)) channels += Mask_DeepBack; channels += Mask_DeepFront | Mask_Alpha; channels -= Mask_Z; } void _request(int x, int y, int r, int t, ChannelMask channels, int count) override { ChannelSet reqchan = channels; getNeededChannels(reqchan); input0()->deepRequest(DD::Image::Box(x, y, r, t), reqchan, count); } void engine(int y, int x, int r, const DD::Image::ChannelSet& cs, DD::Image::Row& row) override { DeepOp* deepIn = input0(); if (!deepIn) { foreach(z, cs) { row.erase(z); } return; } bool doingZ = cs.contains(DD::Image::Mask_Z); bool doingDeepFront = cs.contains(DD::Image::Mask_DeepFront); bool doingDeepBack = cs.contains(DD::Image::Mask_DeepBack); DD::Image::DeepPlane deepRow; DD::Image::ChannelSet engineChans = cs; getNeededChannels(engineChans); if (!deepIn->deepEngine(y, x, r, engineChans, deepRow)) { Iop::abort(); foreach(z, cs) { row.erase(z); } return; } DD::Image::ChannelSet chans = cs; chans -= Mask_Z; chans -= Mask_Deep; foreach(z, chans) { for (int i = x; i < r; i++) { row.writable(z)[i] = 0; } }; while (x < r) { float* Zpix = doingZ ? (row.writable(Chan_Z) + x) : nullptr; float* Zfrontpix = doingDeepFront ? (row.writable(Chan_DeepFront) + x) : nullptr; float* Zbackpix = doingDeepBack ? (row.writable(Chan_DeepBack) + x) : nullptr; if (Zpix) *Zpix = 0; if (Zfrontpix) *Zfrontpix = INFINITY; if (Zbackpix) *Zbackpix = INFINITY; DeepPixel deepPixel = deepRow.getPixel(y, x); DD::Image::ChannelSet requiredChannels = DD::Image::Mask_DeepFront | DD::Image::Mask_Alpha; if (_volumetricComposition) { requiredChannels += DD::Image::Mask_DeepBack; } const bool isValidDeepPixel = deepPixel.channels().containsAll(requiredChannels); if (isValidDeepPixel) { if (_volumetricComposition && DetectOverlappingSamples(deepPixel)) { DeepOutPixel samples; CombineOverlappingSamples(deepRow.channels(), deepPixel, samples); CompositeSamples(samples.getPixel(deepRow.channels(), DeepPixel::eZAscending), chans, row, x, Zpix, Zfrontpix, Zbackpix); } else { CompositeSamples(deepPixel, chans, row, x, Zpix, Zfrontpix, Zbackpix); } } x++; } } int getViewableModes() const override { return eViewableMode2D; } static const Description d; static const Description d2; }; static Op* build(Node* node) { return new DeepToImage(node); } const Op::Description DeepToImage::d(::CLASS, "Image/DeepToImage", build); const Op::Description DeepToImage::d2("FromDeep", "Image/DeepToImage", build);