Hi Jordan, You can create a new layer from within your Op, no need to have an "addchannels" node upstream.
I don't have a full example at hand right now, but you just need to set the desired out_channels in _validate, and turn on your newly created ChannelSet. Ex: // say pw is the Channelset managed by your pworld knob copy_info(); set_out_channels(Mask_RGBA + pw); // if you want to force it to output just RGBA and your new layer. Otherwise, out_channels defaults to Mask_All info_.turn_on(pw); // turn on the new layer if it didn't exist AddChannels is part of the NDK examples, so have a look in there for more details. Also, just to add to some of the good tips that Steve and Nathan have given you, I would recommend that you use the PixelIop::in_channels() virtual method to work out the logic of which channels should reach pixel_engine. That should help you keep pixel_engine cleaner, and avoid checking whether a certain channel exists or not. The idea is that in_channels() is passed the channels that are being requested by a downstream Op, and you can use that to work out what channels need to be passed to pixel_engine(). A good example is Saturation.cpp from the NDK examples, which turns on all RGB channels if either of them is requested. Hope that helps. Cheers, Ivan On Sun, May 20, 2012 at 10:20 PM, Jordan Olson <jorxs...@gmail.com> wrote: > Oh, oops, realized my engine wasn't looping while X < R, so it was > just looping once per row! > I no longer have freaky weird rows (looking like bad memory addresses)!! > > And the new layer works IF I make a "addchannels" node upstream. I > presume then that this is normal behaviour for Nuke- a pixel operator > won't make/write new channels if they are not allocated uptree! > > So... this sort of answers both my questions :P > > In other news I've figured out how to attach the debugger to Nuke- so > this will help break things down for sure. > > Thanks for your help guys! > > > On Mon, May 21, 2012 at 2:25 PM, Jordan Olson <jorxs...@gmail.com> wrote: > > I realized that foreach was a macro defined in the NDK- but I couldn't > > figure out where! thanks for pointing that out. > > > > In my code, 'pw' is an array of channels, which is controlled by a > > Channel_Knob. (I understand that the standard channels (Chan_Red, > > Mask_Blue, etc.) is an enumerate, but what about custom gui set > > channels? in my case I'll have point_world.x, point_world.y, > > point_world.z) > > > > I've got that working. There is a knob controlling a bool called > > "setup"- and in my engine if the knob is enabled, then it copies from > > the user specified channels pw[3] into the set "channels". > > > > So far so good- except within Nuke if I use the PixelIop inherited > > "channels" knob to create a new layer, and test if it is copying from > > pw[3] into that- the new layer stays blank. (though I tested a > > DrawIop, and it seems have no problem creating new layers with > > inherited behaviour) > > Also-- it's a bit buggy- but if I toggle the checkbox on and off, with > > the channels set to "rgb"-- it starts reading messed up buffers and I > > get all sorts of random colored funky lines (that look like rows that > > are being read wrong). I'm fairly certain that the row is simply > > accessing the wrong memory banks because it looks like that- but I > > can't figure out I've done wrong. > > > > So two issues : > > - creating a new layer from my pixelIop's "channels" knob doesn't > > really seem to create it properly or allocate memory > > - messing with the controls and then switching things off seems to > > mess up my RGB channels > > I'm still fairly new to all this, so would appreciate your insight. > > Below is my pixel_engine. > > Cheers, > > Jordan > > > > > > > > > > void PointSample::pixel_engine(const Row& in, int y, int x, int r, > > ChannelMask channels, Row& out) > > { > > > > if (setup) > > // If point world setup is set, copy specified pw channels into > > pixelIop knob "channels" > > { > > foreach(z, channels){ > > > > const float* pw_ptr = in[pw[colourIndex(z)]] + x; > > if (pw_ptr == NULL) // thanks Steve! > > out.erase(pw[colourIndex(z)]); // copied > from some of the NDK > > source code, seems to work > > else > > { > > float* out_ptr = out.writable(z) + x; > > std::copy(pw_ptr, pw_ptr + r - x, > out_ptr); // copied from some > > of the NDK source code > > } > > } > > } > > else > > { > > foreach(z, channels){ > > // somehow in this case, with enough fiddling, > RGBA starts reading > > really weird, like the row memory addresses are wrong > > const float* z_ptr = in[z] + x; > > float* out_ptr = out.writable(z) + x; > > *out_ptr++ = *z_ptr++; > > } > > } > > } > > > > > > > > On Fri, May 18, 2012 at 4:16 AM, Steven Booth <sbo...@legend3d.com> > wrote: > >> That's what I assumed, but I wanted Jordan to confirm. (and yes, I > would concur as regards ChannelMask and ChannelSet). > >> > >> Given that assumption, however, let me say this... > >> > >> Jordan, first realize that 'foreach' isn't a C++ primitive; it's a > macro, defined thus at line 187 in ChannelSet.h: > >> > >> #define foreach(VAR, CHANNELS) \ > >> for (DD::Image::Channel VAR = CHANNELS.first(); VAR; VAR = > CHANNELS.next(VAR)) > >> > >> So, it evaluates to a simple 'for' loop that sets the 'VAR' parameter > to the 'first()' channel in the set, and iterates over the defined channels > using the 'next()' method until 'next()' returns NULL. 'VAR' must, > therefore be a 'Channel', and 'CHANNELS' is a ChannelSet. Since in your > example the 'VAR' is 'z', then yes, this will be a Channel. > >> > >> Logically, you can think of a ChannelSet as an arbitrarily large set of > channels. In fact, it's implemented as a bit array, the index into which > is the channel 'number'. A Channel is an enumerated constant consisting of > the channel numbers. Thus 'Chan_Red' is defined at line 29 in Channel.h > thusly: > >> > >> Chan_Red = 1 > >> > >> Masks, on the other hand, are a separate enumeration consisting of the > mask required to isolate the specific channel in the bit set. Thus, since > 'Chan_Blue' has the value '3', the Mask_Blue will mask bit 3 of a > ChannelSet constant (i.e. 0x00000004). > >> > >> This whole thing is confusing, I think, because Nuke originally only > permitted a maximum of 32 channels (i.e. one 32-bit word), and Masks made > sense. As VFX grew, it became necessary to have way more, and hence the > migration away from a mask-based implementation (which is very fast), to a > set-based implementation (I can hear Jonathan's chair squeaking as he leans > forward to type LOL) > >> > >> In the current implementation, the two structures are designed to play > nicely. Thus, you can instantiate a ChannelSet by handing it a Mask, for > example: > >> > >> ChannelSet red(Mask_Red); > >> > >> Hope that helps a bit. > >> > >> Steve > >> > >> > >> > >> -----Original Message----- > >> From: nuke-dev-boun...@support.thefoundry.co.uk [mailto: > nuke-dev-boun...@support.thefoundry.co.uk] On Behalf Of Nathan Rusch > >> Sent: Thursday, May 17, 2012 8:51 AM > >> To: Nuke plug-in development discussion > >> Subject: Re: [Nuke-dev] Inexperienced NDK simple question on pixelIop > channels > >> > >> >From what I can tell, 'pw' is an array of 'Channel's, probably a knob > storage var (meant to represent the channels picked as P-World). > >> > >> In your foreach, 'z' will be a Channel. > >> > >> As for ChannnelSet vs. ChannelMask, I'm not in front of the NDK headers > right now so I could be misremembering, but I believe one of them is slowly > being phased out in favor of the other. I think ChannelMask is on the way > out, but needs to be kept around for the time being for source > compatibility. > >> > >> -Nathan > >> > >> > >> On May 17, 2012, at 7:32 AM, "Steven Booth" <sbo...@legend3d.com> > wrote: > >> > >>> Jordan, > >>> > >>> Before I deal with this, one question. What is your definition of > 'pw', because it can't be a 'ChannelSet'. Is it an array of ChannelSet's? > An array of 'Channel's? > >>> > >>> Steve > >>> > >>> -----Original Message----- > >>> From: nuke-dev-boun...@support.thefoundry.co.uk > >>> [mailto:nuke-dev-boun...@support.thefoundry.co.uk] On Behalf Of Jordan > >>> Olson > >>> Sent: Wednesday, May 16, 2012 4:01 PM > >>> To: Nuke plug-in development discussion > >>> Subject: Re: [Nuke-dev] Inexperienced NDK simple question on pixelIop > >>> channels > >>> > >>> Hey Steve, > >>> thanks heaps for your writeup! To give you an idea of my background, > I've been comping and python scripting Nuke for a few years, but only > recently attended a class for C++ and am diving into the NDK. So I'm still > fairly new to the NDK and C++ in general. > >>> > >>> > >>> When you explained that 'channels' may only contain channels being > requested of the node by nodes downstream, that was a pretty revolutionary > perspective change for me! > >>> > >>> Though adding the if(ch_pw) doesn't prevent the node from crashing, I > think we're getting somewhere. > >>> > >>> A couple questions; > >>> > >>> -- When running foreach(z, channels); I presume based on your > explanation that "z" does not represent an integer? for some reason I was > thinking it represented an integer (which is why I used it to index pw[z])- > because I assumed "z" would be an integer range from 0-3. > >>> If I understand you right, "z" could actually be a "Depth.Z" channel > and not an integer like 1. So unless the point world knob contains Depth.Z > (which it wouldn't) this would always be NULL. > >>> > >>> -- How are the ChannelMask and ChannelSet classes different from each > other? (and even with the class method PointSample:in_channels() > ChannelSet& is defined as "mask" which I find confusing). > >>> > >>> I'm re-reading the documentation again- although I'm hacking together > code from alot of different source examples, I still don't really get how > to bring in a specified layer and access those channels.. > >>> > >>> Cheers, > >>> Jordan > >>> > >>> > >>> > >>> On Thu, May 17, 2012 at 3:43 AM, Steven Booth <sbo...@legend3d.com> > wrote: > >>>> Jordan, > >>>> > >>>> > >>>> > >>>> I think I see what might be the problem here. You define ch_'pw' > >>>> like this > >>>> > >>>> > >>>> > >>>> Channel ch_pw = pw[z]; > >>>> > >>>> > >>>> > >>>> And then use it like this: > >>>> > >>>> > >>>> > >>>> const float* pw_ptr = in[ch_pw] + x; > >>>> > >>>> > >>>> > >>>> Here's the secret: You have absolutely no guarantee what 'channels' > >>>> contains. 'channels' are the channels *being requested of you by the > >>>> downstream node*. If you hook a shuffle up to your node (Op), and > >>>> shuffle Depth.Z into R, then 'Depth.Z' is going to be placed into the > 'channels' > >>>> ChannelSet passed to your _engine call. > >>>> > >>>> > >>>> > >>>> If, then, your 'point world' ChannelSet isn't requested, or isn't > >>>> fully requested, then pw[z] is going to eventually return NULL. That > >>>> makes 'ch_pw' NULL, and when you do the 'in[ch_pw]', *that* is going > >>>> to be null, which makes pw_ptr NULL, which kind of makes: > >>>> > >>>> > >>>> > >>>> float a = *pw_ptr++; > >>>> > >>>> > >>>> > >>>> somewhat (well. more like 'really') invalid. > >>>> > >>>> > >>>> > >>>> What you always need to do is make sure the channel you're processing > >>>> is actually being asked for. that your channel references are > non-null so: > >>>> > >>>> > >>>> > >>>> Channel ch_pw = pw[z]; > >>>> > >>>> If (ch_pw) { > >>>> > >>>> . code that uses 'ch_pw' > >>>> > >>>> } > >>>> > >>>> > >>>> > >>>> So, the inner code is only used if 'ch_pw' is not null. > >>>> > >>>> > >>>> > >>>> Hope that helps > >>>> > >>>> > >>>> > >>>> Steve > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> -----Original Message----- > >>>> From: nuke-dev-boun...@support.thefoundry.co.uk > >>>> [mailto:nuke-dev-boun...@support.thefoundry.co.uk] On Behalf Of > >>>> Jordan Olson > >>>> Sent: Tuesday, May 15, 2012 5:56 PM > >>>> To: Nuke plug-in development discussion > >>>> Subject: [Nuke-dev] Inexperienced NDK simple question on pixelIop > >>>> channels > >>>> > >>>> > >>>> > >>>> hey fellow Nuke developers! > >>>> > >>>> I'm writing a pixelIop node at the moment, and having difficulty > >>>> figuring out some code. > >>>> > >>>> > >>>> > >>>> I have an extra knob for "Point World" channelset, and to test it, > >>>> I'm trying to copy the pixel values from this set into the standard > >>>> channels specified by the user. (default RGBA). > >>>> > >>>> However it's crashing, and I think I need to implement something like > >>>> the following example taken from the IDistort Iop code: > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> // missing channels will crash, use black instead: > >>>> > >>>> Channel uu = uv[0]; > >>>> > >>>> Channel vv = uv[1]; > >>>> > >>>> if (!intersect(tile.channels(), uu)) > >>>> > >>>> uu = Chan_Black; > >>>> > >>>> if (!intersect(tile.channels(), vv)) > >>>> > >>>> vv = Chan_Black; > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> However this ^ is from an Iop node, and I'm having a crash on a > >>>> PixelIop. Is there a similar function I could implement on my pixel > operator? > >>>> > >>>> Here is my code below, slightly simplified for readability. > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> ............ > >>>> > >>>> > >>>> > >>>> void PointSample::_validate(bool for_real){ > >>>> > >>>> copy_info(); > >>>> > >>>> set_out_channels(Mask_All); > >>>> > >>>> } > >>>> > >>>> > >>>> > >>>> void PointSample::in_channels(int input, ChannelSet& mask) const { > >>>> > >>>> mask += (pw[0]); > >>>> > >>>> mask += (pw[1]); > >>>> > >>>> mask += (pw[2]); > >>>> > >>>> } > >>>> > >>>> > >>>> > >>>> void PointSample::pixel_engine(const Row& in, int y, int x, int r, > >>>> ChannelMask channels, Row& out) { > >>>> > >>>> foreach (z, channels) > >>>> > >>>> { > >>>> > >>>> const float* inptr = in[z]+x; > >>>> > >>>> const float* END = inptr+(r-x); > >>>> > >>>> > >>>> > >>>> Channel ch_pw = pw[z]; > >>>> > >>>> // This doesn't compile because the Pixel Iop has no > >>>> tile functionality > >>>> > >>>> /* > >>>> > >>>> if (!intersect(tile.channels(), > >>>> ch_pw)) > >>>> > >>>> ch_pw = > >>>> Chan_Black; > >>>> > >>>> */ > >>>> > >>>> > >>>> > >>>> const float* pw_ptr = in[ch_pw] + x; > >>>> > >>>> float* outptr = out.writable(z)+x; > >>>> > >>>> > >>>> > >>>> while (pw_ptr < END) > >>>> > >>>> { > >>>> > >>>> float > >>>> a = *pw_ptr++; > >>>> > >>>> > >>>> *outptr++ = a; > >>>> > >>>> } > >>>> > >>>> > >>>> > >>>> } > >>>> > >>>> } > >>>> > >>>> > >>>> > >>>> ............ > >>>> > >>>> > >>>> > >>>> > >>>> > >>>> cheers if you could point out why this is crashing! > >>>> > >>>> Jordan > >>>> > >>>> _______________________________________________ > >>>> > >>>> Nuke-dev mailing list > >>>> > >>>> Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > >>>> http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev > >>>> > >>>> (CONFIDENTIALITY NOTICE: The information contained in this email may > >>>> be confidential and/or privileged. This email is intended to be > >>>> reviewed by only the individual or organization named above. If you > >>>> are not the intended recipient, or an authorized representative of > >>>> the intended recipient, you are hereby notified that any review, > >>>> dissemination or copying of this email, or the information contained > >>>> herein is strictly prohibited. If you have received this > >>>> communication in error, please notify the sender by return email and > >>>> delete this email from your system. Thank You.) > >>>> > >>>> > >>>> _______________________________________________ > >>>> Nuke-dev mailing list > >>>> Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > >>>> http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev > >>>> > >>> _______________________________________________ > >>> Nuke-dev mailing list > >>> Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > >>> http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev > >>> (CONFIDENTIALITY NOTICE: The information contained in this email may > >>> be confidential and/or privileged. This email is intended to be > >>> reviewed by only the individual or organization named above. If you > >>> are not the intended recipient, or an authorized representative of the > >>> intended recipient, you are hereby notified that any review, > >>> dissemination or copying of this email, or the information contained > >>> herein is strictly prohibited. If you have received this communication > >>> in error, please notify the sender by return email and delete this > >>> email from your system. Thank You.) > >>> > >>> _______________________________________________ > >>> Nuke-dev mailing list > >>> Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > >>> http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev > >> (CONFIDENTIALITY NOTICE: The information contained in this email may be > confidential and/or privileged. This email is intended to be reviewed by > only the individual or organization named above. If you are not the > intended recipient, or an authorized representative of the intended > recipient, you are hereby notified that any review, dissemination or > copying of this email, or the information contained herein is strictly > prohibited. If you have received this communication in error, please notify > the sender by return email and delete this email from your system. Thank > You.) > >> > >> > >> _______________________________________________ > >> Nuke-dev mailing list > >> Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > >> http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev > _______________________________________________ > Nuke-dev mailing list > Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ > http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev >
_______________________________________________ Nuke-dev mailing list Nuke-dev@support.thefoundry.co.uk, http://forums.thefoundry.co.uk/ http://support.thefoundry.co.uk/cgi-bin/mailman/listinfo/nuke-dev