Beginner Canvas Tutorial 03

Aaron KentAaron Kent Posts: 66 ✭✭
edited April 2016 in Tutorials

make use of the closest attribute node to create a simple deformation

Cheers
AK

Comments

  • malbrechtmalbrecht Fabric for Houdini Posts: 752 ✭✭✭

    Moin, Aaron,

    fantastic stuff - thank you so much for taking the time!

    I find this tutorial especially enlightening to why I prefer writing 2-3 lines of code to constructing the function graphically. While I do see the advantage of getting to a result by wiring up properties and functions (it "feels manual", in a good way), I could imagine that even with this rather simple setup a coffee break might throw you out of your flow and you'd need a while to understand what the hell you did there :-)

    One thing I am trying to get myself into is using subgraphs more. I did that in the "mesh-painting" tutorial where I threw all the randomization stuff into a subgraph to get it out of the (visual) way in the main graph. I think I need to get used to this way of stacking functions "3d" in a way, if I want to use the Canvas in the future.
    Sure, backgrounds (to group function areas) can help to some degree (especially since you can drag a background and it will carry its node along), but the inter-tweening of wires will still be hard to grasp (for me at least).

    Anyway, if I can be of any help with learning a programming language (like KL - I personally find it closer to C, Basic or even PHP than to Python), drop me a note, I'd be more than happy to try my best.

    Marc


    Marc Albrecht - marc-albrecht.de - does things.

  • Aaron KentAaron Kent Posts: 66 ✭✭
    edited April 2016

    Thanks Marc. My short term term goal is to learn some rudimentary coding basics that will allow me to inspect KL code and build the equivalent node graph. I have absolutely no coding background whatsoever (except some basic javascript knowledge from using expressions in After Effects) When I get to the KL code window in Canvas I have some inkling what I am seeing but not enough to understand the sequence of commands, syntax and symbols involved. I also have a very limited knowledge of mathematics but I am hoping to slowly grow that through using canvas as a learning tool. I have access to codeacademy.com (free site - pretty great) and also a full lynda.com account. If anyone on here could point me towards the best beginner tutorials on either site to do to be able to at least read written KL and understand it would help me most.

    Cheers

    AK

    also here's a video which approximates the learning curve as I am experiencing it:

  • malbrechtmalbrecht Fabric for Houdini Posts: 752 ✭✭✭
    edited April 2016

    Hi, Aaron,

    :lol: on the learning curve ... sorry that you feel that way, for me getting into KL was more like a flatline - that raptor depicts how I feel when I look at "noodle art" (canvas) To each his own, I guess ...

    As for learning: Sorry, I am neither familiar with what Lynda offers nor with codeacademy. My personal history is more like "every halfway sane computer language should basically work like all the others, it's just dialects ..." or "know one and you know all". To me it's more about solving the problem at hand in a "programming way of thinking", then simply look through the documentation what functions and what syntax/semantic each system requires to reproduce the solution.

    I wanted to create a tutorial on "scripting" (just haven't found the time), that would go out on a leg and claim that all you need to know to write programs (to "code" or to "script" or to "whatever") is two paradigms: If and while (or "for").

    The idea being, that a computer can only really do two things: Repeat the same shit over and over again without making mistakes (in that a computer is better than me) and make a distinct decision based on facts and a clear, concrete set of conditions (in that a computer is better than me).

    for/while repetition

    The repetition is - in most computer languages - a construct made of a "for" or a "while" command. This tells the computer that whatever comes after that command is to be understood as a CONDITION. While the stuff after "while" is "true", everything in the block that follows that condition is to be repeated until Dr. Knob calls the rabbits.
    The variant "for" only differs so far as it may have a "set" of repetitions defined, like "do the whole bunch of silliness FOR every item you find in ..."

    Example (this is no real computer language, just a logic example)

    While 1=1 do
       print "I am so stupid"
    Next
    

    Or (again, no real language, just the logic):

    For index in 1 to 10 do
       print "I am still stupid"
    Next
    

    Without explaining what each single token here does, I hope you get the idea. In KL - just like in most modern computer languages - the "for" loop is the most common construct, because you are mostly dealing with a limited set of items. Example: For every vertex/point in a polygon mesh, some operation is to be done. Once the program is done with all vertices, the loop (that's the name for that repetition) ends by itself, because it ran out of items.

    Size i; 
    

    This tells the program that the "counter" it should use is called "i" and that it is of type "Size" (or UInt / unsigned integer)

    for (i=0 ; i<10 ; i++)

    This tells the computer that everything AFTER that statement (see below) is to be repeated as long as the counter "i" has a value between its starting value (0) and the maximum accepted value 10. The semantic here is:

    for is the command itself
    () designate the boundaries of "variables" or "properties" or, in this case, the conditions for the "for" command
    inside the brackets three components are defined, separated by a semicolon. The first statement, telling the computer what to do BEFORE the loop starts:
    i=0 actually is a mini program, setting the counter "i" to a value of 0.
    Then the semicolon ends that step and the second step defines UNTIL when the loop is to be run:
    i<10 is a "condition". You could have program code here, function calls, whatever - the computer (Fabric) just wants to know if this block is "true" or "false". It is true if the result of this block is a boolean "true". So, as long as i is smaller than 10 (not 10 itself), the result is "true". If i is 10 or larger, the result is "false". You do the same logic in canvas on a "if" node.
    The third block tells the computer (Fabric) what to do after each single run of the loop is ended. Here
    i++ is a "programmer's short form" for "increase the counter i by 1". You could write "i=i+1", that would be exactly the same. But programmers are unbelievably lazy - and that is by far the biggest understatement ever made after Dr. Knob invented fourdimensional toast. Most of the completely-bogus and absolutely non-understandable code you will find is driven by two maximes: Be as cryptic as possible to secure either your state as a Wizard or a God of computer programming OR your job. Second: Exercise as minimum manual labor as anyhow possible. Every keystroke is one less you can do in your life.
    So "i++" it is, in roughly about 101% of all cases.

    So what does that statement do? 1) Set i to 0. 2) Check if i is still below 10. 3) increase i by 1.
    Now where is the stuff that is to be carried out AFTER the computer has inspected i and found it smaller than 10?
    That is something where different computer languages will "look and feel" differently. In most "classic" languages you will have a block surrounded by curvy brackets ( "{" and "}" ). Everything inside that block of brackets is to be repeated.
    Some languages expect each code element to be ended by a semicolon - just like the separation in the "for" statement. Others expect end-of-lines. I prefer having a clear ";" as the end designation of a command.

    So this "code" would print "I am slightly less stupid now" 10 times:

    for(i=0;i<10;i++)
       {
       print "I am slightly less stupid now";
       }
    

    In KL you would write
    report("I am slightly less stupid now");
    instead of the "print" line. As long as the output of that node is in any way exposed to the canvas' output, you should see the report coming through.

    This might be your first program in KL.

    If you want me to babble on the second single thing a computer can do - the "if" - let me know. I don't want to ruin your weekend :-)

    Marc


    Marc Albrecht - marc-albrecht.de - does things.

  • Aaron KentAaron Kent Posts: 66 ✭✭
    edited April 2016

    Thanks Marc! - I am going read through this a bunch this weekend while looking at some KL buried inside the nodes. Really appreciate your time on this.

    for (i=0 ; i<10 ; i++)

    So what does that statement do? 1) Set i to 0. 2) Check if i is still below 10. 3) increase i by 1

    this statement alone just saved me about a week of mental hardship and woe.

    thanks!

    AK

  • malbrechtmalbrecht Fabric for Houdini Posts: 752 ✭✭✭
    edited April 2016

    OK - I take that as a "go for it, I am lost anyway" then ...

    Conditions / if

    The basic idea of "if" is already covered in the "for" statement's second block. An "if" statement tells the computer that some condition definition will follow and that - again, in most languages "embraced by brackets" - some block of code should be executed IF the condition is true. There are some slight variants, but this is the logic:

    if (1=1) then
      print "this is kind of obvious"
    end if
    

    Like in the "for" statement the condition is set in normal round brackets. Whatever follows the "if" statement is executed only if the result of what is inside the "()" is true.
    1 is, most of the time, 1. So this logic statement will be considered "true" and the report is output.

    Not all computer languages make use of the "then" statement, it is considered "visually distracting", although some languages go the other way around and have action commands everywhere. For example, in some languages a "for" loop would look like this:

    for a in 1 to 10 do
    ...
    

    The more common notation is "command", "brackets", "code". So an if statement - in KL and most classic computer languages - will look like this:

    if ( 1 == 1 ) 
      {
      report ( "Please explain the double =");
      }
    

    The double "=" is a necessary "visual glitch", because most computer languages allow you to execute code inside a condition. In other words, these languages allow you to call a function that may return "true" or "false" or, as in the example with "if (1 = 1)" you would be dealing with a command that tries to assign the value "1" to a variable (see below) named "1". Depending on which language you use, this may result in an error, a true or a false - most languages will not allow you to assign a value to a value, however.
    So the "==" distinguishes an assignment ("set the counter i to a value of 0") to a comparison ("is the counter i currently 0?"). This is simply something you have to get used to, most computer languages use "==" for comparisons, "=" for assignments. There is a variant with 3 "=" ("if a===0"), but we are going to ignore that for the moment, as it is both dialect depending and not often needed (btw. it means "is a EXACTLY 0?" and is used in cases where a could have a value of "true", "false" or a numeric value - semantics!).

    Now, you don't want to know if 1 is 1, probably. This is where the side step variables comes in. A "variable" (like the "i" we used as a counter above) is, like in school math, a placeholder for any value. A variable as such could hold text, numbers, even polygon meshes. In most computer languages you need to define what "type" a variable has - in KL you do that either in the input/output port definitions or inside the code by a statement like the above:

    Size i;

    ... telling Fabric that i can hold values from 0 to ..., unsigned integer only. "Size" is a KL expression for the more generic "UInt" (short for "unsigned integer", a purely positive fraction-less number).

    Vec3 a;

    would create a variable named "a" and define it as a vector with 3 components (a standard 3d-vector that is).

    Such a variable can be assigned values (or "content" if you like). Saying "i=0" means: Set the variable to a value of 0.
    If you can assign a value to a variable, it makes sense to check if that variable has changed its value. That is exactly what the second block in the "for" statement does:

    if ( i<10 ) ...

    As long as the statement (the little code fragment) inside the brackets is true, whatever follows the command (after the closing bracket) is executed.

    if ( i==10 ) ...

    ... would work just as well, as long as i gets increased by 1, starting at 0. The problem with checking for a specific value (is i 10?) leaves out cases where, for whatever reason, i has gotten larger. 11 would not stop the loop if you only checked for i==10.
    Sometimes inside the code that is repeated in a loop you mess around with the counter variable - e.g. if you want to REDO something. Imagine you have a deformer where points can, but need not to, change the points BEFORE them. So you might want to repeat a part of the loop and would set the counter (inside the curvy bracket program part) to "i=i-2;"
    In this (weird, dirty) example the loop would end, i have a value of 2 below its current value. Then the for loop (taken we are still in the above example scenario) would increase i by 1 (because the loop is going to repeat), now i has the previous value minus 1, repeating point operations on the PREVIOUS point.
    This is dirty and bad practice, because it might lead to death loops (the loop might never end if i constantly got reset to some previous values, never reaching the "end" condition).

    This is where an if statement might help.

    Inside the loop, that might run forever, you could have a "runaway condition check". You could have an if-statement that checks for error conditions.
    Keeping the example simple, imagine this scenario:

    Integer i;
    
    for ( i = 0 ; i < 10 ; i++)
       {
       report("I am silly");
       i=i-2;
       }
    

    Instead of using "Size", I am this time using "Integer" for the counter. This is done for a reason: When the loop comes to its first conclusion (i is still 0), i gets set to -2 (because 0 - 2 is -2). A "Size" (being only positive) can not be "-2", so, depending on the language, you would get a program error or undefined behavior.

    The loop would now run forever, outputting the most obvious observation about me.

    Now let's introduce a "runaway check":

    Integer i;
    
    for ( i = 0 ; i < 10 ; i++)
       {
       report("I am silly");
       i=i-2;
       if ( i < 0 ) 
           {
           report("Not only that, I am also a bad programmer");
           i=11;
           }
       }
    

    This program basically is the same as before.
    But after i is being reduced by 2, the if statement checks if i is, for whatever reason, below 0 (which is the case in the first run already). IF (sic!) i is below 0, the code inside the curvy brackets is executed, giving a rating of my craft AND setting the counter to 11.
    In fact, I could just set i to 9, because after the loop ends its run, i gets increased by 1, setting it to 10. And 10 is NOT smaller than 10, so the loop would end just as well!

    Side note: Another way of breaking out of a loop is the command "break;" This command exits out of the loop-bracket-block immediately without executing any further code inside the block, but instead continuing with what comes after the closing curvy bracket.

    Second side note: If you only want to execute a single command after a conditional statement (if) or as a loop, most languages allow you to omit the brackets for the code.
    So this program would do the same 10x print as before:

    Size i;
    for (i=0;i<10;i++)
       report("Yeehaw!");
    

    Omitting the curvy brackets only works on a single line (a single command), however.

    (Side side note
    Here Python is different. Python works even without the curvy block brackets all together, only using the indentation of the program line. Personally I find that horrible, visually distracting, highly irritating in more complex code - but that is, of course, a question of habit, routine and ... age :-)
    But this is one example why I find Python one of the few languages not well usable for learning foundations of programming. It simply has a few paradigms that are very different to most other languages. The claimed idea is that Python is more "clear to read", but, as with most things in life, Python's designers considered their own perspective the only correct one and everyone who takes a different approach is considered simply wrong. That is, I think, another property of software developers: There can only be one correct perspective on things, the universe and everything. Theirs.
    end of side side note)

    Conclusion

    Everything outside loops and conditions is "bells and whistles".

    By this I mean: Computer languages are not limited to "if" and "for", obviously. But computer programming logic is. Repeat something until the modifications you have done to it fits your expectations.
    Solving a problem in terms of computer programs, in this simplistic view, boils down to: Can I solve the problem by comparing values, adjusting things, comparing values, adjusting things ... and do some simple math in between?

    I hope this is of any help ... I realize it does not explain how KL works, but, as I said before, I think that KL and other programming languages really only require you to memorize their respective semantics: How are code blocks separated or grouped (line indentation in Python, brackets "everywhere" else), is there a colon after a statement (in Python after an if or not "everywhere" else), do you need semicolons etc.

    But the computer can only do what you tell it to do (the stuff inside a program or a loop, which is a program) and check if it is supposed to do it again.

    Other perspectives are possible, likely to be better and probably less silly. But this is my approach.

    Have a great weekend, nevertheless!

    Marc


    Marc Albrecht - marc-albrecht.de - does things.

  • Aaron KentAaron Kent Posts: 66 ✭✭

    Awesome - one last very dumb question - if I am down within the function writing module in Canvas and I write that code to make it print something 10 times - how do I fire off said code so it would happen inside the logged messages window?

    AK

  • malbrechtmalbrecht Fabric for Houdini Posts: 752 ✭✭✭
    edited April 2016

    if I am down within the function writing module in Canvas and I write that code to make it print something 10 times - how do I fire off said code so it would happen inside the logged messages window?

    The node in which you are writing that code will only get executed if it is somehow connected to the out-side of the canvas. So you need to "fake" something, like defining a String out on the node and expose that string property to the "outside world". You don't need to do anything with that output, just exposing it will trigger a basic execution.
    Whenever you change the code in the node and save the node, canvas will get re-executed and you should see the reports.

    On more complex setups where you don't want arbitrary "exposition helpers", just add a "report" node and connect that to any property of any node and expose the report node's output - that way you can "report" the content of a Vec3 for example.

    Marc


    1.PNG 17.9K
    2.PNG 4.2K

    Marc Albrecht - marc-albrecht.de - does things.

  • EricTEricT Administrator, Moderator, Fabric Employee Posts: 304 admin

    @Aaron Kent I'd go to the Javascript learning path on Codecademy. Since KL and Javascript have very similar syntax it'll get you going pretty well. They ramp up slowly through the concepts too. I think it's a great resource for learning the similar syntax and also for learning programming concepts too.

    Eric Thivierge
    Kraken Developer
    Kraken Rigging Framework

  • Aaron KentAaron Kent Posts: 66 ✭✭

    @EricT - thanks - two birds with one stone as I could use more javascript know-how for after effects.

    AK

  • Aaron KentAaron Kent Posts: 66 ✭✭

    @malbrecht - why does it report "yeah" twice when plugged into the port? shouldn't it report it only once?

  • malbrechtmalbrecht Fabric for Houdini Posts: 752 ✭✭✭

    why does it report "yeah" twice when plugged into the port?

    that, my dear Jeeves, you need to ask the FabricGuys. Somehow the graph gets executed twice when you edit code in a node. Almost always. It's nothing "code-related", it's ... like gravity. It's there. You cannot explain it. :)

    Marc


    Marc Albrecht - marc-albrecht.de - does things.

  • nsjognsjog Posts: 5

    A lot of useful reading and would love to see more from all of you, it is very helpful when trying to understand and learn, thank you.

Sign In or Register to comment.