Topic outline

  • Kia ora Guest user

    Welcome to CGI506 Technical Development 1, S2-20. In this course you will be developing basic skills and knowledge of programming for animation and game development and to develop custom tools and functions for a successful production pipeline.

    On completion of this course you will be able to:

    1. Investigate and compare different programming languages used for animation, visual effects and real time applications. 
    2. Evaluate the effectiveness of different scripting/programming languages for selected applications. 
    3. Select and use a number of different scripting languages to achieve the desired effects and tools.  
    4. Create custom tools to facilitate a production scenario. 

    Alongside the class time and your project work, you will be provided with extra learning material, videos and tasks to help you improve your skills.  Work at your own pace spending roughly 4 hours a week on these. 

    All courses in this programme include an assessment of professionalism. Professionalism includes your active engagement in class activities, your ability to communicate with your peers and tutor, how you work in a team and more importantly how you manage your self.

    Usually we cover one session per week. Note this course content and schedule, may be adjusted as we understand more about our needs as a group of learners. 

    • Designing an efficient production pipeline 45
    • Using industry standard programming language to build tools the pipeline 45
    • Professionalism 10

    Assignments: 3
  • This page links you to the extra tools you will be using while studying.

    Forums: 2 Text and media areas: 2
  • Welcome to the first week of Technical Development for pipeline.

    We're going to be learning about the technical aspects of pipeline, equipping you with the tools to automate tasks and develop your own tools, which will make you more capable in this exciting industry.
    There are perhaps three ways technical skillsets can be loosely conceptualized in our industry.

    • Technical Artists: These are the definitive workforce at any studio. They primarily complete creative tasks, however they may use a line of code here, a snippet there, to accelerate their workflows and increase their value to the companies they work for. Additionally, because they develop their own workflows for increasing productivity in their own realms, they can become indispensable for their employers with their skill sets.
    • Technical Developers/Directors: Also known as Pipeline Developers, developers provide the backbone of any studio's pipeline, helping data flow from point A to point B, researching and developing novel workflows, and debugging production issues. At a junior level of pipeline developer may be concerned with making tools for artists, dialog boxes that gather information and buttons that automate things. At an advanced level pipeline developers may do work with database interfaces, production tracking, web applications, mass data processing, and so on.
    • Programmers: Typically specialists with a computer science background. You are more likely to see programmers working on low level tasks like memory management, pixel processing, rendering engines, database schema, production engineering, and so on. Programmers are likely required to have advanced knowledge of mathematics and computer science.

    Our goal here is not to turn you into programmers, but to give you additional technical skills which will help you work more effectively and give you an edge. And at the more advanced levels 6 and 7 in this degree, technical developers will be taught skills suitable for a pipeline developer position in a studio. But for now, by giving you the keys to APIs, you will be capable of doing things which most other people cannot do.

    Reasons to code

    https://youtu.be/Dv7gLpW91DM

    What is the difference between Scripting and Programming languages?
    Terminologies may vary around the world, but we define this as thus:
    A programming language is one which requires compiling into machine byte code in order to be run on a computer. They are more specialized, but require more work.
    A scripting language is one that can be interpreted by the computer and run directly by the user, with any optimization happening invisibly. They usually run in a special scripting environment, and are optimized for the user to write efficiently.
    Python gets a special mention here, because it happens to have its feet in both camps. Developers call it a general-purpose programming language that is "also used for scripting". There is good reason why Python is catching on as the language of choice for many industries, not just in games, animation, and VFX.

    Mental Models
    To succeed in our industry you will be well served by a lifestyle of open-minded curiousity about the world we live in. Take your time, experience daily life with open eyes.
    Notice and develop an interest in phenomena. See how light interacts with objects, how wind affects a tree, how flower petals form. Note how vines grow, how ocean waves move. The changing reflectiveness of water surface.
    This sort of knowledge will help inform your mental models of reality, in turn increasing your effectiveness as a technical artist or pipeline developer.

    Overview of Scripting Languages

    Conventionally low level languages have been defined as machine readable code, and high level meaning human readable code. Perspective is relative, however and one can still think of C++ as being lower level than Python. Or additionally that scripting languages are higher-level then programming languages.

     levels_languagges

    Most software packages are written from the ground up in C++ and compiled, or built, for specific operating systems versions. But the applications we are most concerned with implement a more user-friendly scripting interface through an API, or Application Programming Interface. This can either be accessed using the applications native language (e.g. MEL for Maya) or through any other implemented language, most commonly Python.

    Many companies integrated their own proprietary languages into the packages to give end-users more ability. Here is a quick list of packages and their supported languages, with bold indicating native (specialized) language for that package only:

    Blender : Python
    Houdini : HScript, VEX (C++), Python
    Maya : MEL, Python,
    Nuke : TCL, Python
    Unity : C#, UnityScript (JavaScript), Boo
    Unreal : BluePrints, C++, Python

    Notice something in common between almost all of them? Python! But before we get there, we are going to begin with MEL in order to lay a better foundation for understanding APIs moving forward.

    Introduction to MEL in Maya
    Time to get practical and open up Maya.

    https://vimeo.com/302734048

    The first thing one must always do in a new language is attempt to run a "Hello World" program. For MEL this is pretty simple:

    print "Hello World";

    Next up, a brief introduction to the Script Editor in Maya, command history, writing commands, and dropping into the Shelf.

    MEL API Documentation:

    This is an important resource to have open while you explore the Maya command history and begin to write your own scripts.

    http://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/Commands/

    Using proc to declare functions (collections of commands)
    https://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/mel/PROC_procs.html

    Tutorial: 3D fractal cubes
    https://www.instructables.com/id/Introduction-to-MEL-Scripting-in-Maya-3D-Fractals/

    Exercise idea:
    Abstract artwork using the rand function

    Exercise idea:
    Automatically duplicate by writing a function which interpolates between object A and object B and makes X number of duplicates between in Translation. Bonus: Also interpolate Rotation and Scale.

    Glossary:
    API Application Programming Interface
    3D Three Dimensional
    MEL Maya Embedded Language
    CG Computer Graphics
    OOP Object Oriented Programming
    VFX Visual Effects
    OBJ The Wavefront 3D object file format is good I have I think the first module almost done for text
    FX Effects
    GUI Graphical User Interface
    DAM Digital Asset Management
    FPS Frames Per Second
    DCC Digital Content Creation
    TCL Tool Command Language
    IDE Integrated Development Environment
    R&D Research and Development
    VEX Vector Expression Language
    FBX Autodesk Filmbox file format
    ILM Industrial Light & Magic

    Forum: 1 Interactive Content: 1 Quiz: 1
  • Text and media area: 1 Interactive Content: 3
  •  

    We are going to be learning quite a bit more about Python in this session, basic features and skills that will enable you to begin logically assembling programs. We'll individually cover important topics one at a time.

    Indentation:

    To make for cleaner and easier reading, python by design operates at indented levels. This means whenever you have a conditional statement or loop, it will operate only on the code which is indented below it. You can think of these as “clauses” or paragraphs. Having correct indentation is mandatory for correct python execution.

    Other software languages (for example, C) require the use of semi-colons (;) to end lines and braces {} to mark the start and end of clauses/paragraphs. And yet programmers of those languages will often indent their code anyways!

    For example (this is C, not Python!) Indentation is the programmer’s decision, C doesn’t care. C only cares about the braces, “{“ and “}”.

     

    So Python simplifies this by relying on indentation only, (which is more readable in my humble opinion)

     Iterables:

    An iterable is anything that can be passed to a loop or queried multiple times for items.

    Sets and Tuples:

    We are already familiar with lists, so I will describe now what sets and tuples are in Python. All of these objects are “iterable” which is to say that they can have any number of items and that Python makes it easy to loop through them.

    Where lists let you store same item multiple times, and remembers the order you store them, Sets are fundamentally different because they will not store the same item twice. They can be most useful for cleaning out multiple copies of the same item. 

    Tuples in Python can be thought of as being like lists or sets but with one exceptional property: they are “immutable” or in plain words, cannot be modified. And as such they have very few methods (functions) you can use on them.

    Here’s how the three look:

    >>> things = [1, 4, 3, 8, 2, 2, 2]
    >>> type(things)
    <type 'list'>
    >>> set(things)
    set([8, 1, 2, 3, 4])
    >>> tuple(things)
    (1, 4, 3, 8, 2, 2, 2)

    Notice how a set changes the items by removing copies?

    And in Python, you can instance any by name, the only requirement is that as an argument they receive are iterable (that’s why you see a list inside of each function):

    >>> x = list([1, 2, 3])
    >>> y = set([1, 2, 3])
    >>> z = tuple([1, 2, 3])

    Or by shorthand, the only difference is the kind of bracket used:

    >>> x = [1, 2, 3]
    >>> y = {1, 2, 3}
    >>> z = (1, 2, 3)

    Remember all these are iterables.

    Don’t be intimidated by all the brackets, it’s actually quite simple. Square brackets always indicate a regular good’ole list. Parentheses indicate a tuple (which is only good for reading from) or a set, if the word “set” is shown. Sets however can be made similarly to a dictionary by using braces but with keys only, and no values.

    >>> # this is a dictionary, note the semicolons matching values to their keys 
    ... d = {'house_key': 'front door', 'second key': 'back door'}
    >>> # this is a set, will not retain order but will not store copies either
    ... s = {'eins', 'zwei', 'drei'}

    If, Elif, and Else statements:

    When our programs execute, we will frequently want to switch behavior based on some condition. This is where if statements come in handy. The key word if is followed by an expression that when evaluates True, python will execute your code below it. Otherwise it will execute one “else” section if you should include it.

     if (expression goes here):
    Execute this code here
    elif (expression goes here):
    Execute this code instead
    else:
    Nothing was executed above, so run this instead.

    Note that elif, and else statements are optional. You can use a standalone if statement by itself, any number of attached elif statements.

    Moving on: 

    # favourite number
    guess = raw_input(‘Guess my favourite number between 1-10’)
    if guess > 3:
    print ‘Too high!’
    elif guess < 3:
    print ‘Too low!’
    else:
    print ‘Well done, 3 is my favorite number!

    # favourite colour
    guess = raw_input(‘Guess my favourite colour!’)
    if guess == ‘chartreuse’:
    print ‘Wow, lucky guess! You must have read the source code’
    elif guess != ‘blue’:
    print ‘Nope, not :’, guess
    else:
    print ‘Ew!’

     Can you guess in which case the last clause would print ‘Ew!’? 

    Let's look at Pseudocode:

    From Wiki/Infogalactic : Pseudocode is an informal high-level description of the operating principle of a computer program or other algorithm. It uses the structural conventions of a programming language, but is intended for human reading rather than machine reading.

    Let’s say that you want to do apply a burnt-in frame number for every image in a sequence. However you know that the sequence could optionally be stereoscopic-- or in other words-- one image for each eye, left and right. But optionally this could be single sequence.

    Your pseudocode could look like this:

    If sequence is stereo?
    Get two items list containing left and right eyes sequences
    Else (otherwise)
    Get one item list containing the sequence
    For every image in sequence
    Apply burn in

     Formulating your thoughts this way will go a long ways to helping you plan your code better. Let’s expand on our example:

    Is the sequence stereo?
    For each eye in left and right
    Get sequence
    Otherwise (else)
    Get one item list containing the sequence
    For every image in sequence
    Get path, and frame number
    Put together arguments for a function that applies the burn-in.
    Execute function

    Why pseudocode?

    The whole idea behind pseudocode, is to articulate one’s thoughts into text. The process one goes through in doing this will further clarify the ideas they have and potentially identify any challenging areas they’ll need to focus on.  Using pseudocode is the first step to implementing a program will help you plan more effectively.

    Exercise : Write pseudocode for something non-computer-related, Such as your choice of breakfast this morning, or how a keeper might manage food supplies for the animals at the zoo. Or what might a Tesla onboard computer do when it sees a large orange object moving on one camera?

    So what can we do with iterables? Loops!

    There are a couple of ways to loop in Python -- the for loop, and the while loop.

    Let’s look at each in turn:

    The way for loops work is like this, and note the trailing semicolon (:)

    for [Choose your variable name here] in [Something loopable or iterable here]:
    # Run all code in this block, with [variable name you chose] being updated each
    # time

    Here’s an example:

    my_list = [‘apples’, ‘feijoas’, ‘zebras’]
    for item in my_list:
    print item

    This will print each item on new lines:

    >
    apples
    feijoas
    zebras

    Let’s say you want to loop through a range of numbers. Let’s introduce you to a new function in Python, "range".

    for i in range(10):
    print i

    … will give you something like this

    0
    1
    2
    3
    ...

    The range function simply returns a list of numbers, from 0 to the argument you give it, unless you give it two:

    > print range(3,6)
    [3, 4, 5]
    > print range (2)
    [0, 1]

    Wait, why is 0 included but 10 isn’t?

    Python, like many programming languages, counts from 0, not 1. The first item or “index” in any list, will be 0, not 1.

    This may take a bit of getting used to, but it’s intuitive once you get the hang of it. Many things on the computer start from 0, whether it is memory values, hardware addresses, or hexadecimal numbers. 

    While Loop:

    While (statement here evaluates to True) -- loop here.

    A simple demonstration: How many times will this loop?

    x = 2
    while x < 10:
        x = x + 1

     

    Dicts and unpacking:

    The for loop will take any object you give it, and try to “iterate” through it by requesting it’s items. In the case of a dictionary, this’ll be the dictionary’s keys.

    french_dict = {‘hello’ : ‘bonjour’, ‘thank you’ : ‘merci’}
    for x in french_dict:
    print x
    # will print:
    # hello
    # thank you

    But what if you wanted to justs print the values in a dictionary? Or both the key and value?

    for x in french_dict.values():
    print x

    will print:

    bonjour
    merci

    Or:

    for key, value in french_dict.items():
    print value, key

    will print:

    bonjour hello 
    merci thank you

    How does it work?

    Well firstly, when you call items() on a dictionary, you’ll see a list of pairs returned like this:

    > print french_dict.items()
    [(‘hello’, ‘bonjour’),  (‘thank you’, ‘merci’)]

    Can you recognise the tuples inside the list? So when the loop iterates through dict.items() it will receive one tuple at a time.

    In python you can also unpack:

    > x, y, z = [‘one’, ‘two’ three’]
    > print y
    two

    So when we run this:

    for k, v in french_dict.items():

    Each time the loop is run, k and v will be unpacked from each tuple returned from the dictionary items().

    A note on variable names:

    In python a variable name must not contain spaces, cannot start with a number, or contain special characters.

    So these are not ok:

    1apple
    a##le
    $apple
    an apple

    But these will work:

    apple1
    apple_sauce
    x
    AppleJuice

    Take a breather:

    Whew. We’ve learned alot about python objects, and the basic types we can use.

    Next up we are going to learn about functions, which can take arguments and do things. This is the backbone of Python, and a good developer will break up their code into many small reusable functions. A function is like naming your code, much the same way variables name strings and numbers.

    https://www.youtube.com/watch?v=asjQNZn7vng

     

    Functions:

    The basic function looks like this:

    def [name goes here]( [zero or more “arguments” go here] ):
    [code goes here that is run when this function is called]
    [and optionally a return call, otherwise this function returns None]
    return [zero or more variables/objects]

    Or, here are some examples for you to type in and run:

    # this doesn’t take any arguments
    def print_none():
       print "there's nothing here!"

    # this only takes one argument
    def print_one(arg1):
       print 'arg1 is : {}'.format(arg1)

    # this only takes two arguments
    def print_two(arg1, arg2):
       print 'arg1 is : {} and arg2 is {}'.format(arg1, arg2)

    # having an asterisk before a var name means it will pack into a list, can have any number of arguments
    def print_all_args(*args):
       for arg in args:
           print args

    # by the time the interpreter gets here, the functions are defined
    # so we can call them with arguments now!
    print_all_args(‘as’, ‘many’, ‘as’, ‘I’, ‘want’, ‘even’, 139546)
    print_one(‘John’)
    print_two(‘John’, ‘Smith’)
    print_none()  # takes no arguments

     In Python def is short for “define function”. After you give it a name, adhering to the same rules about naming variables that we explained previously, You can then define any another number of variables “arguments” within the parentheses which will be passed into the function.

    The asterisk * is not often used this way in Python, but when it appears before a variable name, inside a set of parentheses, it will pack those variables into a list.

    Now functions can also define default variables, which hold a certain value by default unless the caller supplies the argument.        

    def inventory(yorkies=10, labradors=5, siamese=0):
       print 'We have {} yorkies, {} labradors, and {} siamese'

    > inventory(5, 8)
    We have 5 yorkies, 8 labradors, and 0 siamese
     
    > inventory(siamese=20)
    We have 10 yorkies, 5 labradors, and 0 siamese

    But probably the most important feature about functions is the ability to return a variable or object. Here we have a function which returns True if we have more yorkies then labradors.

    def is_more_yorkies(yorkies=0, labradors=0):
       if yorkies > labradors:
           return True
       else:
           # we have more labradors, or the same number
           return False

    > is_more_yorkies(5,4)
    True
    > is_more_yorkies(5,8)
    False
    > result = is_more_yorkies(10,10)
    > print result
    False 

    Time for a challenge:

    I’m going to challenge you to a text based game. First write pseudocode for it, then complete the program.

    The pseudocode could look something like:

    # multi choice story game
    # opening scenario
    print description of opening scene and give user a choice of 2 numbered options
    get raw input from user and store as variable
    if variable is equal to one, go to first scenario
    elif variable is equal to two, go to second scenario
    after a few multi choice storyline, finish program with life or death, success or failure 

    Reading & Writing Files:

    Reading and writing files in ascii (text) format or binary is easy in Python.

    Let’s begin by creating a new file and naming it “data” in the same directory as your working python files. (this can be done on repl.it or your local system Python if you are following with that.)

    It can contain something like this:

    Hi I am data!
    This is the second line.

    And finally, the last line.

     Next, create a new working file and type in the following example:

    from os.path import exists

    input_file = 'data'
    output_file = 'data_2'
     
    print 'copying from {} to {}'.format(input_file, output_file)

    # we could do these two on one line too, how?
    in_file = open(input_file)
    indata = in_file.read()
    in_file.close()

    print ‘Input file has a size of {:d} bytes'.format(len(indata))
    print 'Does the output file exist? {}'.format(exists(output_file))
    print 'CTRL- C to abort or Enter to continue and copy'
    raw_input()

    out_file = open(output_file, 'w')
    out_file.write(indata)
    out_file.close() 

    print 'Program complete.' 

    When we run this we can see that the program creates the output file before writing. You can compare now and see that the contents are the same.

    There are some new things to see here. We have two import lines at the top, and a new built-in function called “open”. We use this function to open a file handler for both reading and writing to files in Python. You can see the first argument it takes is a file path, and the 2nd argument is a string representing the access mode, or in our case “w” which stands for write access.

    Also new is the “exists” function, you can give this function a path to a file on disk and it will return true or false depending on if the file exists on disk.

    Errors & Exceptions:

    Often you’ll encounter an error which causes your program to abort. In Python, errors are called exceptions and it is these that you will be dealing with.

    An error can come from anywhere, perhaps one wrote the command incorrectly (that dreaded Syntax Error), or a file is not found, or perhaps something else has gone inexplicably wrong.

    Fortunately there are ways of catching errors and handling them in a graceful way.It’s time to introduce the “try” and “except” clause. These operate a little bit like “if” and “else” conditionals, whereas if Python encounters an error in the “try” clause, it will immediately execute any matching “except” statements.

    Let’s make a function which returns True if the given variable is a number, and False if a given variable is not.

    Firstly, we see an error raised if we try to convert a string into an integer:

    >>> int('blah')
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    ValueError: invalid literal for int() with base 10: 'blah'

    So, let’s make a function that handles this gracefully.

    def is_number(var):
       try:
           int(var)
           return True
       except ValueError:
           return False

    We saw the error encountered first was called the ValueError, and by specifying this as an exception, we could handle the error gracefully without interrupting our program. 

    Interactive Content: 4
  •  

    In this session we are going to be learning about Maya and Nuke APIs (Application Programming Interface) with a view towards equipping you to picking up any API you happen to look at. Maya and Nuke probably have the most commonly utilized interfaces in this industry.

    We are also going to be looking at more of Python’s built in functions that will help you along with your programs. 

    Getting started with Maya:

    Firstly, you have the ability to run single commands in Maya using the execution box: You can toggle between MEL and Python by pressing this button:

    Then you may run commands in the field immediately to the right of it, by typing in and pressing Enter.

    Secondly and more importantly, you have the script editor. Once open, click the “+” for a new tab, and press Python to open a Python tab if you don’t already have one open.

    This is where your MEL knowledge will come in handy, because almost any command you can run in MEL is also accessible by Python. Try it:

    from maya import cmds
    cube_parts = cmds.polyCube()

    Thirdly, you should familiarize with, and bookmark, any relevant reference material you need to lookup features you need. Autodesk documentation has pages on how to set up the environment for advanced users, but we’ll get back to that.

    (Instructors, be aware if these are the latest versions of the docs)

    PyMEL Documentation:

    http://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/PyMel/why_pymel.html

    Our course here at NMIT is going to focus on PyMEL’s Custom API rather than Maya’s native cmds module. You should already have basic familiarity with the cmds module from your time spent with MEL.

    PyMEL gives a more pythonic, easier to understand, and easier to deploy approach to working with Python in Maya. It was developed by technical directors at Luma Pictures in California, and Autodesk was impressed enough by it to decide to include it with Maya by default.

    Maya Python & MEL commands Reference

    http://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/Commands/

    Maya Scripting (Linked from the F1 help homepage)

    http://help.autodesk.com/view/MAYAUL/2018/ENU/?guid=GUID-703B18A2-89E5-48A8-988A-1ED815D5566F

    To do:

    Making tools in Maya:

    Don’t forget that to make tools in Maya, you can do this the same way as you would with MEL: by selecting text in the script editor, dragging and dropping into Shelf of Maya.

     At this point we would like you to use the following resources, please skip the Nuke material:

    Dragon-34167Here be (useful) dragons. Do the first in this series, use this as homework.

    "Building Maya Interfaces with Python: "

    https://vimeo.com/42848594

    See here for a link to a first go at including the LOADER.py

    https://drive.google.com/drive/folders/1-szGP2SDdY_6-s5D0cA5tW302dhZSokJ?usp=sharing

    The following set provides you with access to the full set.

    https://vimeo.com/showcase/2136748

    This SECTION IS UNDER REVIEW Getting started with Nuke:

    Nuke has a script editor much like Maya, which can be opened the same way as any panel.

    NUKE Python Developer’s Guide

    https://learn.foundry.com/nuke/developers/113/pythondevguide/

    And the Python Reference for commands:

    https://learn.foundry.com/nuke/developers/113/pythonreference/

    To do:

     

    Your first nuke tool:

    Let’s make a simple function which can be loaded into nuke at startup time and run by a shortcut key of our choosing.

    On Windows, navigate to -- ($USER should be replaced with your username)

    C:\Users\$USER\.nuke

    On linux or mac, the .nuke will be in your home folder.

    /home/$USER/.nuke

    Inside create an empty text file and name it “menu.py”. This will be a python script that is run on Nuke’s startup.

    Inside, write the following lines:

    import nuke
    import getpass


    user = getpass.getuser()
    user = user.capitalize()

    def make_cool_blur():
    b = nuke.nodes.Blur()
    b.setName('{}sAwesomeBlur'.format(user))

    nuke.menu('Nuke').addCommand('{}sMenu/make cool blur'.format(user), 'make_cool_blur()', 'ctrl+alt+m') 

    Now, run nuke and try pressing the “control+allt+M” key.

    Presto! You just wrote your first Nuke pipeline tool!

    There’s a few things going on here. getpass.getuser() can be used on any operating system to get the username of the current user. (This you can also do with the OS module, although that method can vary between operating systems)

    nuke.menu(), addCommand are both only found inside of Nuke's environment. menu() can be used to access any menu at the top of Nuke, the left-hand column of node menu icons, or even many of the right-click menus inside of Nuke.

    More information about menus and tools can be found in this documentation, it's worth reading.

    https://learn.foundry.com/nuke/developers/113/pythondevguide/custom_ui.html#creating-a-custom-menu-item

    This is the basic starting point of how studios or professional artists extend Nuke.

    A Graphic User Interface (GUI) teaser:

    Although we will not be exploring user interface libraries in detail during this course, I just want to give you a quick preview of how easy it will be to get started:

     from PySide import QtGui
    label = QtGui.QLabel("Hello World")
    label.show()

    If you run this in either Nuke or Maya’s script editor, you should see a small popup dialog with “Hello World” shown on it.

    Challenges:

    • Make a python function which does something in Nuke or Maya.

    • Brainstorm some ideas for tools that could automate tasks you do -- you’re going to want these ideas later. This could be duplicating something automatically, maybe porting something between applications,

     

    A local install:

    If you haven’t already, I would recommend installing python 2.7.15+ (3.x is OK too) locally on your machine to follow along with some of these examples which will be easier when you can access your local computer. (But not python 3.x unless your tutor recommends otherwise)

    https://www.python.org/downloads/release/python-2715/

    Let’s go on a walk :

    We’re going to look at os.walk which is used to list files and folders recursively.

    I am doing this in a local python interpreter which has access to my hard drive. You can do this exercise in any application script editor or standalone python interpreter.

    We’ll start with importing os and then running walk on a directory which has subfolders and files at different levels. I will approach it in an exploratory manner.

    >>> import os
    >>> os.walk(r'D:\1_DEV\Misc')
    <generator object walk at 0x04878698>

    Ah, now that’s interesting. Remember generators from our segment on iterables?

    It’s basically a deferred iterable -- instead of returning all of it’s items at once, it gives us a generator object which we can loop through, which will return as it goes. This is to defer and spread out processing time.

    So to see what this generator will return, I must either convert it into a list or iterate through it using a loop:

    >>> for t in os.walk(r'D:\1_DEV\Misc'):
    ...   print t
    ...
    ('D:\\1_DEV\\Misc', ['.idea'], ['PySide2_test.py'])
    ('D:\\1_DEV\\Misc\\.idea', ['inspectionProfiles'], ['Misc.iml', 'modules.xml', 'workspace.xml'])
    ('D:\\1_DEV\\Misc\\.idea\\inspectionProfiles', [], ['profiles_settings.xml'])

    Note that the parentheses indicate read-only tuples, and on each line we see three things: a string, followed by two lists.

    If you examine these closely, what do these correspond to?

    The first string gives you the path to a root directory, the following list gives a list of directories in the same root, and thirdly, a list of files in the same root directory.

    So what could we do with this? We could make a prank program that pretends to delete everything in a given path.

    The pseudo code for could look like this:

    Set path to root directory or user’s home folder
    Print scary message about self-destructing
    Run os.walk on path
    For each root string, list-of-files in os.walk,
    For each file in list-of-files,
    Add together path and filename to get full path
    Print scary deleting message with full path
    Print scary message that all is done and deleted

    You could even add a tally count of files “deleted”, and the total amount of bytes (divide by one million to get megabytes).

    The student who writes the scariest looking harmless program gets extra recognition:)

    Game Developers take note!

    If you are thinking about game development, I would recommend checking out Pygame or Pyxel. This is an excellent way to get your feet wet in basic game programming and algorithms, with the low level interfacing already taken care of for you. There are even tutorials to help you get started:

    https://www.pygame.org/

    https://www.pygame.org/wiki/tutorials

    Pyxel is simpler, and easier to learn.

    https://github.com/kitao/pyxel

     



    Interactive Content: 2
  •  

    In this session we will be looking at how to document your code, then moving onto one of our most advanced topics so far, which is Object Oriented Programming.

    Docstrings and Documenting your code:

    In Python it is essential to document your code. Especially when one begins working with other people, a team, or in a company. You will almost never be the only developer working on any particular program, so it's essential to get into the habit of documenting as you go. Fortunately Python makes this pretty easy.

    This is a docstring in a function:

    def build_lamborghini():
       """This function builds and returns a Lamborghini"""
       # Code goes here …..

    Docstrings can span multiple lines like this:

    def build_porsche(horsepower=220):
       """
       This function builds and returns a popular German sportscar.
       """
       # the keyword “pass” tells Python not to do anything here or get upset at the empty function
       pass

    Or they can be at the top of the module like this, before the imports.

    (The hash is inserted by some editors, but is not always present, don’t worry about it)

    # -*- coding: utf-8 -*-
    """
    This module contains some functions for making our lives easier.

    The first function is called brush_teeth() and does what you might expect.

    You can use it like so:
    >>> from habits import brush_teeth
    >>> brush_teeth()
    Teeth Brushed!
    """
    import os, sys, random

    # … Code goes below this

    This is called a module docstring.

    The great thing about docstrings is that they can be easily accessed.  Remember the help() function we learned in week 2?

    >>> help(build_porsche)
    Help on function build_porsche in module __main__:

    build_porsche(horsepower=220)
       This function builds and returns a popular German sportscar.

    Or by directly using Python’s built-in method, a double score attribute visible from dir().: (The backslash letter “\n” tells Python that this is a newline)

    >>> build_porsche.__doc__
    '\n    This function builds and returns a popular German sportscar.\n    '

    And later when we get to documenting our Python modules automatically, we will rely heavily on docstrings to do the majority of the work for us.

    Now many companies have different standards and conventions for docstrings, but I will draw your attention to one of the most popular which we currently use. And that is the Google style docstring.

    It consists of 3 parts: the description, the arguments, and the return type. It looks something like this:

    def build_porsche(name, horsepower=220, wheels=4):
       """
       This function builds and returns a popular German sportscar.

       Args:
           name (str): Name for this car
           horsepower (int): How powerful to make the engine
           wheels (int): How many wheels it should have

       Returns:
           Porsche(class): An instance (copy) of our porsche
       """
    # code goes here

    Each of the 3 parts I mentioned are optional, you don’t have to include a Returns section if your function does not return anything.

    Read briefly through this document, and don’t be too concerned with understanding some of the funky stuff like classes and @properties, we’ll be getting to that later.

    https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html

    Now for our exciting topic.

    Object Oriented Programming (or OOP, for short):

    In Python virtually everything is an object. Python is very flexible when it comes to designing our objects, combining or rearranging as we see fit, or making entirely new ones. Everything that comes with Python is flexible and open for us to modify. There will even be an example of this later.

    The concept of Object Oriented Programming is one that applies to any advanced language, not just python. It’s the idea of having a blueprint or as we call it-- Class, which is the definition of an object before gets created. The class definition acts as a blueprint, and when called, produces a “instance” working copy of it.

    First, we start by making a class:

    class Superhero(object):
       """
       This is a blueprint for extraordinary humans.
       """
       pass

     You can see by the keyword “pass” that this definition currently does nothing.

    Also, note that “object” is being supplied as an argument to our class. However class definitions are a little different than function definitions, and all the arguments given here actually used as “superclasses” for inheriting properties from. We will come back to this.

    Finally, notice I already applied a docstring to this class.

     

    Let’s play with this Superhero class interactively:

    >>> Superhero
    <class '__main__.Superhero'>
    >>> Superhero()
    <__main__.Superhero object at 0x05522410>
     
    >>> ironman = Superhero()
    >>> thanos = Superhero()
    >>> ironman
    <__main__.Superhero object at 0x055FD2D0> 

    Don’t worry about all the extra information here, but notice that the first time python tells us we have a class (blueprint) and each time after when we call it with (), python gives us an instance, a working copy. A class on its own is not something you can work with, just like how a blueprint of a car is not something you can drive.

    Let’s add a variable to this class, and also a function for fun. For brevity, I’ll leave out the docstring.

    class Superhero(object):
       iq = None
     
       def speak(self):
           print 'Give me your infinity stones!'
     

    thanos = Superhero()
    thanos.iq = 200
    print thanos.iq
    # prints 200
     
    thanos.speak()
    # prints “Give me your infinity stones!”

     Now-- functions on classes are called “methods”, Although they are essentially the same thing with one subtle difference. Did you notice the keyword “self”?

    By default, methods on classes must always start with “self” as the first argument.

    self” Provides us access to the instance we are calling, so you can actually design the methods to access itself. This can be confusing in theory, so let’s demonstrate by adding another function.

    class Superhero(object):
       iq = None
     
       def speak(self):
           print 'Give me your infinity stones!'
     
       def brag(self):
           print 'And my IQ is {}!'.format(self.iq)
     
    thanos = Superhero()
    thanos.iq = 200
    thanos.brag()
    # will print “And my IQ is 200!” 

    In theory you can think of it as "brag(thanos)" But the great thing is self will work the same way no matter how you name your variable.

    Note: Python is flexible and you can actually use any name besides "self" for your methods. The word "self" is simply a convention which is useful to Python developers because it makes the code much more standard and easy to understand, even if it’s written by someone else. In all my experience, Python developers have always used “self”. Now if you really wanted to confuse your instructor and classmates, you could change this, though I’m not recommending this at all ;)

    One more thing. Variables defined on the class as we have done it are called class variables, they will actually remain the same between different instances  since we really have defined the variable on the class and not on the instance. So if we want a variable that sticks only to the instance, how do we do this?

    This is where we’ll first see special methods in Python. Whenever you see a name that both begins and ends with double underscores, (__) these referred to native methods python already has. And we can in fact, extend or replace the special methods to change the ways that objects work.

    The most common special method you will see when working with classes is the __init__ method.

    class Superhero(object):
       def __init__(self):
           self.iq = None

    What this does is set up iq as a variable on a per-instance basis. Which means now we can do this:

    thanos = Superhero()
    thanos.iq = 200
     
    ironman = Superhero()
    ironman.iq = 201
    thanos.brag()
    # And my IQ is 200!
    ironman.brag()
    # And my IQ is 201! 

    Inheritance and Overloading:

    This is where the power of object-oriented-programming really begins to show. Most complex working systems rely on inheritance to simplify the code-base, and understanding this will give you an advantage.

    class Superhero(object):

       def __init__(self):
           self.iq = None
     
       def speak(self):
           print 'Give me your infinity stones!'
     

    class Ironman(Superhero):
     
       def speak(self):
           print "Never!! I have {} reasons not to!".format(self.iq)
     
       
    thanos = Superhero()
    ironman = Ironman()
    thanos.speak()
    # Give me your infinity stones!
    ironman.iq = 200
    ironman.speak()
    # Never!! I have 200 reasons not to!

    You can see when we define Ironman, we pass Superhero as an argument or a “superclass”, (also known as “parent class”). This tells Ironman that his blueprint is the same as Superhero.

    Then, we can selectively overwrite, replace, or extend methods found on the parent class.

    You can see how Ironman already had self.iq, and we simply overloaded (overwrote) the “speak” method.

    If you’d like to watch a video on the basics of OOP, here is a 20 minute review. (not 54 as indicated by Youtube). This doesn’t go as in-depth as we do.

    https://www.youtube.com/watch?v=L1eu7m4XFTg

     

    Private attributes (variables):

    It’s time to discuss the concept of “private” variables, which although it has no implementation in Python, it is a common concept found in other languages that has found its way into Python only through developer convention (writing style).

    When we see a variable or attribute that begins with a single underscore, it indicates that the develop himer who wrote this code intended the variable to be “private”. This just means that they don’t expect us to call this variable directly, but rather that it is something that should not be used or accessed directly. However this is only implied convention-- in Python there are no rules in this regard. Naming our variables with or without an underscore will not make any difference in the way the program behaves.

    Here’s an example of how a private variable might be used:

    class Superhero(object):
       def __init__(self):
           self.iq = None
           self._last_eaten = None
     
       def eat(self, something):
           self._last_eaten = something
           print 'Mmmmm tasty'
           
       def previous_meal(self):
           print 'I last ate {}'.format(self._last_eaten)
     
    spidey = Superhero()
    spidey.previous_meal()
    # I last ate None
    spidey.eat('Sardines and Sauerkraut')
    spidey.previous_meal()
    # I last ate Sardines and Sauerkraut

    Making Superheroes Super:

    When working with inherited classes, we may want to extend methods rather than replace them. Python has a keyword for this: “super”. When used, it returns the parent class for use. Here is how it looks in practice:

    class Superhero(object):

     def use_ability(self):
           print 'Powering up to...',

    class Spiderman(Superhero):
       
       def use_ability(self):
           super(Spiderman, self).use_ability()
           print 'shoot webs!'
     
    class SpidermanJunior(Spiderman):
       
       def use_ability(self):
           super(SpidermanJunior, self).use_ability()
           print 'and climb walls!'        

    When run, we see:

    >>> spidey = Spiderman()
    >>> little_spidey = SpidermanJunior()
    >>> spidey.use_ability()
    Powering up to... shoot webs!
    >>> little_spidey.use_ability()
    Powering up to... shoot webs!
    and climb walls!

    We can even do multiple inheritance:
    class A(object):
       def walk(self):
           print 'Walking'
     
    class B(object):
       def swim(self):
           print 'Swimming'
       
    class C(A, B):
       def __init__(self):
           self.walk()
           self.swim()


    >>> c = C()
    Walking
    Swimming

    Whew! You’ve made it this far, it’s time to review the terminology we have learned so far.

    • class

    • superclass

    • methods

    • inheritance

    • private attributes (variables)

    • super

    • instances

    Your goal this week is to go back to some of your programs you’ve written, and carefully consider if they could be re-written in a more object oriented manner. Think about tasks as potentially representing objects rather than procedures. For example, in a text based exploration game, each environment could be a class that inherits from some common environments.

    Be creative!

    If you’re still struggling, or would like further review with any of the OOP concepts we discussed today, I’d recommend this video example where Eli creates a virtual Deck of Cards with OOP.

    https://www.youtube.com/watch?v=t8YkjDH86Y4

     

    Interactive Content: 4
  •  

    We are going to talk about directory structure and laying out your Python programs. We will also look at how to set up the environment for Python, how we can import and execute other files in the directory structure and common troubleshooting tips. going.

    First, let’s choose a folder on your local hard-drive to set up a new project.

    You can call this folder “skeleton” and use it as a basis for future python projects- by copying, pasting and renaming.

    Inside, create four directories, “bin”, “docs”, “python”, and “tests”. Inside of “python” and “tests”, create an empty text file and rename it to “__init__.py”.

    It should look like this.

    └───skeleton
       ├───bin
       ├───docs
       ├───python
       └───skeleton
               └───__init__.py             
       └───tests
        └───__init__.py

    The name "skeleton" is just a placeholder, as you write Python programs you can copy the whole folder and rename them.

    "bin" stands for binary, and simply is a folder for placing directly executable files and programs. Python scripts can go here, but usually only as pointers. The actual modules should go in the Python directory.

    "docs" is for documentation, readme files and HTML documents can go here.

    "tests" is for testing -- we may not get to this this year but you will be learning about it the future.

    Note: Make sure you named the file “skeleton/__init__.py” and not “skeleton/__init__.py.txt”, which can happen easily if you’re on Windows.

    What are the __init__.py files?

    For Python to import a Python file (module) On disk, there are two conditions that have to happen:

    • The path to the folder must be in the environment variable “PYTHONPATH”. This can be done before running your program or while running your program, so long as it is before the import. We’ll show you how to do this.

    • The folder must contain a “__init__.py” file. Python will look for this to indicate that this folder is a python module.

    So let’s do test to show how this all works.

    Take your skeleton folder, and rename both it and the “skeleton” folder inside to “SwedishChef” or something similarly amusing.

    Inside of the formerly named “skeleton” folder (this is the second, inside folder, not the top-level one) that you renamed, next to the __init__.py file create a file called “jokes.py”.

    Inside, we’re going to write a function (or class, if you prefer).

    import random
    jokes = [
       "I don't always herdy dur mur flerpty floopin; but when I do, I yer der shmer dor her der foomty, der shoopin flerpty dur.",
       "We're goofing dur flicky stuben der bork bork bork you betcha",
       "I leeke-a pythun prugremmeeng, it's fuonner thuon shefing yeks",
    ]

    def random_joke():
       # Remember, indexes start from
       return jokes[random.randint(0, 2)]   

    Then fire up your interpreter, or favourite Script Editor in Nuke/Maya.

    We are going to extend the PYTHONPATH while using python, before running the import. If you know how, you could also set the PYTHONPATH before running the application (interpreter, Nuke, Maya, etc).

    import sys
    # sys.path is built from the environment variable PYTHONPATH, same thing
    sys.path.append(r'D:\1_DEV\NMIT_Project\SwedishChef\python')
    from SwedishChef import jokes

    dir(jokes)

    This should give you something like:

    # Result: dir(jokes)
    # Result: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jokes', 'random', 'random_joke']

    We imported our own module, and can see our functions inside.

    Now we could run jokes.random_joke() directly or we could import that first.

    from SwedishChef.jokes import random_joke
    random_joke()
    # Result: "I don't always herdy dur mur flerpty floopin; but when I do, I yer der shmer dor her der foomty, der shoopin flerpty dur."

    It’s working!

    Here we are giving python the path to the folder with a python module inside. What makes a python module? Another folder with __init__.py found inside.

    So for directories to be discovered by Python as modules, they must contain __init__.py. I hope I’ve made that clear! I’ve been caught out many times, wondering “why can’t Python import my module?” only to realize I forgot to put this file inside.

    Requirements Gathering:

    From Infogalactic (Wikipedia):

    In requirements engineering, requirements gathering is the practice of collecting the requirements of a system from users, customers and other stakeholders.

    I like to think of requirements gathering as figuring out what it is my program needs to do, and if I have the knowledge to implement it. At a company it may mean talking to the related staff who have an interest in your program. But on an individual level, it means researching if you can do what you plan to in python. Let’s say you wanted to write an auto-rig script for Maya. Planning would involve answering questions like “can I create and place joints in 3D space?” and “can I structure them in a hierarchy to do what I want?”.

     

    Homework:

    We are also going to be looking at more of Python’s built in functions that will help you along with your programs.

    Built-ins: These keywords already defined in python, and some of them you’ve already seen. Don’t worry if same are beyond you, they’ll make sense later.

    • range
    • and
    • del
    • from
    • not
    • while
    • as
    • elif
    • global
    • or
    • with
    • assert
    • else
    • if
    • pass
    • yield
    • break
    • except
    • import
    • print
    • class
    • exec
    • in
    • raise
    • continue
    • finally
    • is
    • return
    • def
    • for
    • lambda
    • try        

    Go through the list and research which ones you don’t know, and do an internet search to find out more about them. Take notes so you can refresh your memory down the road. It’s not important to know every one, but to have an overview, and to understand the idea behind it.

    To search, you can just add “python” as a keyword, e.g. “python exec”.

    Assessment Brief : Designing efficient production pipeline

    Brainstorm, design, layout the folder structure, and pseudocode a tool of your design.

    First brainstorm a list of ideas that you have for tools, and anything goes. The objective is to brainstorm as many ideas as possible, big or small, good or bad, without yet judging the ideas.

    Secondly, narrow down your list of ideas, and do some research (documentation, internet) around how to implement what you want to do in python, if it so possible, which modules you’d need to use to accomplish this. This is a form of requirements gathering.

    Lay out a directory structure for your tool which can be imported into Nuke or Maya or any python environment. Application integration is optional for this assessment.

    Then finally pseudocode your application in detail to demonstrate you understand the work to be undertaken. This assessment is the design portion of your project, which you will next develop.

     

    Interactive Content: 3
  • We will develop our skills as developers ;-) !

    Run this in your shell:

    >>> import this
    Beautiful is better than ugly.
    Explicit is better than implicit.
    Simple is better than complex.
    Complex is better than complicated.
    Flat is better than nested.
    Sparse is better than dense.
    Readability counts.
    Special cases aren't special enough to break the rules.
    Although practicality beats purity.
    Errors should never pass silently.
    Unless explicitly silenced.
    In the face of ambiguity, refuse the temptation to guess.
    There should be one-- and preferably only one --obvious way to do it.
    Although that way may not be obvious at first unless you're Dutch.
    Now is better than never.
    Although never is often better than *right* now.
    If the implementation is hard to explain, it's a bad idea.
    If the implementation is easy to explain, it may be a good idea.
    Namespaces are one honking great idea -- let's do more of those!

    This is an Easter egg hidden in Python. Meditate on it, and be sure to come back to it in the future. It will mean different things to you as you learn to code.

    Code should do what we expect:
    With the principles of user experience and design, code we write should generally be clear in meaning, and do what we expect. These are the guiding principles of user-centered design, and ones that can help us in designing the code that we write. Generally other people are going to work on our code too, and so, things should work as they’d expect. Now of course if one doesn’t have the experience as a developer, they may not be familiar with conventions or how things should be done, but don’t sweat this. With experience all things become easier.

    This means taking the time as you write to consider how you name and structure things.

    What does it mean to be “Pythonic”?

    From Infogalactic (Wikipedia):

    A common neologism in the Python community is pythonic, which can have a wide range of meanings related to program style. To say that code is pythonic is to say that it uses Python idioms well, that it is natural or shows fluency in the language. Likewise, to say of an interface or language feature that it is pythonic is to say that it works well with Python idioms, that its use meshes well with the rest of the language.

    In contrast, a mark of unpythonic code is that it attempts to write C++ (or Lisp, Perl, or Java) code in Python—that is, provides a rough transcription rather than an idiomatic translation of forms from another language. The concept of pythonicity is tightly bound to Python's minimalist philosophy of readability and avoiding the "there's more than one way to do it" approach. Unreadable code or incomprehensible idioms are unpythonic.

    Use keyword arguments wherever possible:

    My personal take on this, and one observation that we can begin doing straightaway -- is using specifying the full keyword arguments whenever possible. Explicit is better than implicit. For example:

    # no keyword arguments, this is harder to read
    do_something('/path/thing.exr', ['char', 'bg'], True)
    # vs keyword arguments, this is easier to read
    do_something(path='/path/thing.exr', filter=['char', 'bg'], follow_links=True)

    Python also lets you place things inside parentheses, however you like for readability:

    do_something(
       path='/path/thing.exr',     
       filter=['char', 'bg'],
       follow_links=True)

    What are some ways your programs can be improved?

    Optionally, for further reading:

    https://docs.python-guide.org/writing/style/

     

    Editing Python:

    I would like to suggest a couple of advanced editors, Atom or Sublime Text.

    Both can be extended with plugins to make your python editing experience smoother, and easier to read with context sensitive highlighting.

    Atom:Whichever editor you decide to use, be sure to look up an introductory tutorial and explore some of the more advanced features for refactoring code, multi-select, and so on.

    Naming Conventions: which case do I use?

    This is just my personal preference from the studios I’ve worked at. The primary objective is to be consistent in your modules.

    Why use naming conventions? It gives you a sense of what looks good, feels correct in code, and it makes it easier to understand someone else’s code if they follow the same conventions as you do.

    • Variables: Underscore case. “is_validated”, “num_cherries”, “user” are all great variable names. Lower case words separated by underscores.

    • Functions: I also uses underscore case here, but some companies or frameworks use camel case, which looks like “camelCase”. Upper case first-letters of every word except the first word which is all lower case. “validateSequence”.  Also important is to name your functions in a way that indicate what they do, in verb form. Like “submitRender” or “safetyCheckSequence”.

    • Classes: PascalCase. Like camelCase but every word has its first letter capitalized, including the first. E.g. “AbstractSequence” or “PolyCube”.

    • Globals: UPPER-CASE. If it’s a variable, a fixed constant that does not change, but acts as a switch mechanism, we often write it as all upper case. Like “CONFIG”. Use sparingly, all caps is hard to read!

    Interactive Content: 2
  •  

    Continue to work on your in class work from last session. For this session we’re going to be introduced to debugging.

    Debugging Python:

    This is a somewhat advanced skill but has the potential to get you out of a tight spot in the future.

    Debugging is a great and irreplaceable tool-set for any developer to have. So, what is it?

    It is the ability to stop your programs at a given point, inspect the variables, change them, examine the call-stack (which function called which) and step through the code, one line at a time. Debugging is a last resort, when critical thinking cannot resolve the bug. But frequently, it’s more effective than putting print statements everywhere.

    So, we can run our programs directly, using Python like this and specifying pdb. This tells python to execute the script with the given module, “pdb” in our case. PDB stands for Python DeBegger.

    python -m pdb /path/to/script.py

    Now, if we tell Python to use the module “pdb”: let’s try this on a program we write to have an error.

    MY_LIST = ['odin', 'dva', 'tree']

    def cause_error(a_list):
       # this will raise an IndexError
       sliced = a_list[4]
       return sliced

    def main():
       fourth = cause_error(MY_LIST)
       print fourth

    main()    

    Then let’s run this with pdb.

    C:\Python27>python.exe -m pdb D:\1_DEV\NMIT_Project\skeleton\SwedishChef\IndexError.py

    The first thing we see is an interactive prompt. PDB will prompt us before doing anything.

    > d:\1_dev\nmit_project\skeleton\swedishchef\indexerror.py(1)<module>()
    -> MY_LIST = ['odin', 'dva', 'tree']
    (Pdb)

    This is an interactive python prompt, except -- we are currently sitting on the first line of the program!

    All your usual python commands will work, but PDB provides us with an extra set of commands.

    The first thing to know is that -- if you ever hit “Enter” on a blank line in PDB, it will re-run the last command you used, for convenience. We’re going to do this with the short-hand commands, but PDB will understand both “c” and “continue”. We’ll get back to a list of commands after.

    • So first let’s type in “c” for continue and hit enter: then we should see a traceback as our error is hit. Python will say “Running cont will restart the program”.

    • Next type in “l” (lower case L) to look at where we are in the code.

    • We can see the error happened on line 5 (in my case) so let’s type in “b 5” which means breakpoint on line 5

    • Run “c” to restart the program, and hit Enter a second time to run it up to our breakpoint

    • Run “j 6” to jump to the next line, skipping our errored line

    • Run “sliced = ‘test’ “

    • Run “c” to run the program through to completion

    • Finally, press Control+C co close and terminate python.

    Did you see what we did there? We told the program to stop at the line we knew would error with a breakpoint, we jumped past the error, and then defined our variable differently, in order to continue the program through to completion. We modified it as it ran.

    If you are interested in PDB, work through this tutorial, and be sure to examine or copy the table of commands at the end. This is an incredibly powerful skillset that will help you as a developer. (and I speak from experience, when I say that most developers and technical artists in our industry don’t even know how to debug!)

    https://www.digitalocean.com/community/tutorials/how-to-use-the-python-debugger

    There is another way to stop programs anywhere you like when running python normally without arguments:

    import pdb 
    pdb.set_trace()

    This works similarly and you don’t need to specify “-m pdb”. Python will run the program normally until it reaches set_trace() and then will stop at that point and prompt you.

    There is one catch -- PDB can only be used when we have access to an interactive prompt, which means not Maya or Nuke (in GUI mode) but only in an interactive python session.

    There are more advanced remote debugging tools available, (Pydev) which can be used through special applications, but we will get to that another year. If you can master PDB then you’ll be better prepared to handle any other debugging tools in the future.

    Well done:

    You’ve completed 506. Next year we have some exciting things lined up, much more in-depth on application APIs, more advanced python, IDEs, and version control. (Since after all, “you can’t have coffee without the cup”). Maybe we’ll even get to GUIs, creating buttons that do things.

    However I want to stress that if you have an appetite for learning, for teaching yourself things new things, this will really help you excel in this fast moving industry. So if you can, after this course is done -- pick up some tutorials, or a book that you're interested in, and work through it. Commit to a little bit every day. Little by little adds up before long. 

     

    Interactive Content: 1
  • Visual Graphical Node "Flow" Languages

    Graphical scripting systems can be found in the CGI industry, that bridges the gap between expressing a visual thing and using traditional text based scripting notations. 

    An up and coming variant of Python is PyFlow as demonstrated for Maya here:

    https://youtu.be/chnRrr1Qfj8

    A similar approach is prevalent in a number of CGI apps. Houdini uses the "node tree" metaphor as the way to express manipulation of CGI content. 

    https://www.youtube.com/watch?v=7Jg189FyFWs

    Exercise Blueprints in Unreal Engine

    In Unreal Engine "Blueprints" are provided that add behaviour to your assets. The Asset is enhanced by a Blueprint script and carries that with it as you reuse that in your art work. 

    With your NMIT login you can use this tutorial to become familiar with  Blueprints in Unreal:
    https://www.linkedin.com/learning/unreal-blueprint/create-blueprint

    A general introduction to Unreal Engine in developing real-time is provided in the following Essentials tutorial. 
    https://www.linkedin.com/learning/unreal-essential-training-2019/real-time-visualization-with-unreal-engine-4

    Exercise From Blueprints to Blutilities

    Unreal Engine provides manipulation of the Editor using Blueprints scripts that run in the editor. These "Blutilities" are useful for  automating editing of a work in the editor. 

    Follow through the following "playlist" to gain some experience of writing and using Blutilities :

    https://www.youtube.com/playlist?list=PLj4vHMEHbdfw9h8Kfoyt62kencHqTsgzw

    This exercise is guided by the tutor in class - there are some differences as Unreal Engine has been developed.

  • Interactive - is inter-awesome

    The power of the Game Engine comes into play when you get started with developing user interaction with your environment.

    In this section a couple of video based tutorials are presented that provide an experience of developing an interaction in Unreal Engine 4. The following tutorial set has the advantage that it also provides notes that compare Unreal with Unity3D.

    Create a Roll-a-ball in Unreal, with notes that compare with Unity3D

    This series is provided to the public by The Phantom Game Designs developer. It would be polite to subscribe to their channel.

    The series introduces Unreal 4 as it guides you through the development of a Roll-a-Ball game in Unreal, each section includes a comparison with Unity3D, usually towards the end of of the section.

    Let's see you play YOUR Roll-A-Ball game by the end of a session.