03_Tools and Pipeline

PYQT, USD, Best Practices

01_Programming Paradigms

01_Programming Paradigms

01_Event-Driven Programming

Event-driven programming is a programming paradigm where the program reacts to events, such as user actions, sensor inputs, or system-generated signals. Instead of following a strict sequence of commands, the program listens for events and responds when they occur.


Core Concepts 

1. Events

2. Event Handlers

3. Event Loop


Key Components

1. Basic Event-Driven Program

This example demonstrates a simple event-driven system with custom events and handlers.

# Simple Event-Driven Example
class Event:
    def __init__(self, name):
        self.name = name

# Event handlers
def handle_event_1(event):
    print(f"Handling event: {event.name}")

def handle_event_2(event):
    print(f"Handling another event: {event.name}")

# Main event loop
def event_loop(events):
    for event in events:
        if event.name == "event_1":
            handle_event_1(event)
        elif event.name == "event_2":
            handle_event_2(event)

# Example usage
events = [Event("event_1"), Event("event_2"), Event("event_1")]
event_loop(events)

Output:

Handling event: event_1
Handling another event: event_2
Handling event: event_1

2. Keyboard Input Event Handling

Using Python's built-in keyboard library to respond to keypresses.

import keyboard  # Install with: pip install keyboard

def on_key_event(event):
    print(f"Key {event.name} pressed!")

# Attach the event handler
keyboard.on_press(on_key_event)

# Keep the program running to listen for events
print("Press any key (Ctrl+C to exit)")
keyboard.wait()  # Blocks and listens for events

What Happens:


3. Timer-Based Event Handling

This example uses the threading library to trigger events based on a timer.

import threading

# Event handler
def on_timer_event():
    print("Timer event triggered!")

# Set up a repeating timer
def start_timer():
    threading.Timer(2.0, start_timer).start()  # Triggers every 2 seconds
    on_timer_event()

start_timer()

What Happens:


4. Event Handling with PyQt

PyQt is another popular library for GUI development. It relies on signals and slots for event handling.

from PyQt5.QtWidgets import QApplication, QPushButton, QLabel, QVBoxLayout, QWidget

def on_button_click():
    label.setText("Button clicked!")

app = QApplication([])
window = QWidget()
layout = QVBoxLayout()

label = QLabel("Click the button!")
button = QPushButton("Click Me")
button.clicked.connect(on_button_click)  # Connect signal to handler

layout.addWidget(label)
layout.addWidget(button)
window.setLayout(layout)
window.show()
app.exec_()

What Happens:

5. AR Foundation Plane Detection Event

For AR Foundation, use ARPlaneManager to detect planes in an AR session.

using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class ARPlaneDetection : MonoBehaviour
{
    [SerializeField] private ARPlaneManager planeManager;

    void OnEnable()
    {
        planeManager.planesChanged += OnPlanesChanged;
    }

    void OnDisable()
    {
        planeManager.planesChanged -= OnPlanesChanged;
    }

    private void OnPlanesChanged(ARPlanesChangedEventArgs args)
    {
        foreach (var plane in args.added)
        {
            Debug.Log($"Plane added: {plane.trackableId}");
        }
    }
}

What Happens:


Best Practices for Event-Driven Programming in Unity

  1. Use Built-in Events Where Possible:

    • Leverage Unity's UnityEvent, UI events, and physics events instead of reinventing the wheel.
  2. Avoid Overusing Global Events:

    • Delegate-based or static events are powerful but can lead to tight coupling and difficulty debugging.
  3. Unsubscribe When Done:

    • Always unsubscribe from events to avoid memory leaks or unintended behavior.
    void OnDisable()
    {
        myButton.onClick.RemoveListener(OnButtonClick);
    }
  4. Debugging:

    • Use logs or breakpoints to verify that your events are being triggered and handled correctly.
  5. Combine with Coroutines:

    • For delayed or time-based responses to events, pair event handlers with Unity's coroutines.

Unsubscribing from events in Unity (or in C# in general) applies only to the specific listeners (event handlers) you explicitly unsubscribe. It does not globally remove all listeners from the event.

Here’s a breakdown:


How Event Unsubscription Works

1. Only Affects Subscribed Handlers

When you unsubscribe from an event, you only remove the specific handler (method or delegate) you subscribed to it. Other handlers subscribed to the same event remain unaffected.

Example:

using System;
using UnityEngine;

public class EventUnsubscribeExample : MonoBehaviour
{
    public static Action OnCustomEvent;

    void Start()
    {
        // Subscribe two different handlers to the same event
        OnCustomEvent += HandlerOne;
        OnCustomEvent += HandlerTwo;

        // Invoke the event
        OnCustomEvent?.Invoke();

        // Unsubscribe only HandlerOne
        OnCustomEvent -= HandlerOne;

        // Invoke the event again
        OnCustomEvent?.Invoke();
    }

    void HandlerOne()
    {
        Debug.Log("Handler One called.");
    }

    void HandlerTwo()
    {
        Debug.Log("Handler Two called.");
    }
}

Output:

Handler One called.
Handler Two called.
Handler Two called.

2. Why Unsubscription Is Important

Memory Leaks

If an object subscribes to an event but is not unsubscribed before the object is destroyed, it may cause memory leaks because the event keeps a reference to the object, preventing garbage collection.

Example:

void OnEnable()
{
    SomeEventManager.OnGameEvent += HandleGameEvent;
}

void OnDisable()
{
    SomeEventManager.OnGameEvent -= HandleGameEvent; // Unsubscribe to prevent memory leaks
}

Avoiding Unexpected Behavior

If you don’t unsubscribe properly, the event may trigger a handler for an object that is no longer relevant or expected to respond.


3. Applying to Unity Events

For Unity's UnityEvent system, you must unsubscribe the same way to remove a specific listener.

Example:

using UnityEngine;
using UnityEngine.Events;

public class UnityEventExample : MonoBehaviour
{
    public UnityEvent myUnityEvent;

    void Start()
    {
        myUnityEvent.AddListener(EventHandlerOne);
        myUnityEvent.AddListener(EventHandlerTwo);

        myUnityEvent.Invoke(); // Calls both handlers

        myUnityEvent.RemoveListener(EventHandlerOne); // Unsubscribe EventHandlerOne

        myUnityEvent.Invoke(); // Calls only EventHandlerTwo
    }

    void EventHandlerOne()
    {
        Debug.Log("EventHandlerOne triggered.");
    }

    void EventHandlerTwo()
    {
        Debug.Log("EventHandlerTwo triggered.");
    }
}

4. Common Mistakes

A. Unsubscribing from Non-Subscribed Handlers

If you try to unsubscribe a handler that isn’t subscribed, nothing happens. C# handles this gracefully without throwing an error.

Example:

OnCustomEvent -= NonExistentHandler; // No error, but nothing is removed

 

5. Does This Apply to All Events?

Yes, the principle of unsubscribing applies to all types of events:

You must explicitly unsubscribe only the handlers you no longer need.


Best Practices for Unsubscribing

  1. Always Unsubscribe When Appropriate:

    • Use OnDisable or OnDestroy to clean up event subscriptions.
  2. Track Subscriptions:

    • Keep a clear record of what you’ve subscribed to and ensure they’re unsubscribed when no longer needed.
  3. Use Weak References if Necessary:

    • For advanced use cases, consider weak references to avoid holding strong references to objects, preventing memory leaks.
  4. Avoid Excessive Global Subscriptions:

    • Too many global events can make debugging complex. Use scoped or localized events where possible.

Would you like further guidance on managing event subscriptions or specific examples in Unity? 🚀

 


 

Building a Simple Event-Driven Framework

Here’s how you can build a small event-driven framework in Python:

class EventManager:
    def __init__(self):
        self.listeners = {}

    def subscribe(self, event_name, handler):
        if event_name not in self.listeners:
            self.listeners[event_name] = []
        self.listeners[event_name].append(handler)

    def emit(self, event_name, *args, **kwargs):
        if event_name in self.listeners:
            for handler in self.listeners[event_name]:
                handler(*args, **kwargs)

# Example usage
def on_custom_event(data):
    print(f"Custom event received with data: {data}")

event_manager = EventManager()
event_manager.subscribe("custom_event", on_custom_event)
event_manager.emit("custom_event", data="Hello, World!")

Output:

Custom event received with data: Hello, World!

Advantages of Event-Driven Programming

  1. Modularity:

    • Event handlers can be written as independent, reusable functions or modules.
  2. Responsiveness:

    • Ideal for interactive applications where user input or external events dictate program behavior.
  3. Scalability:

    • Can easily add more event types or handlers without major changes to the main program.

Challenges in Event-Driven Programming

  1. Debugging:

    • The flow of execution is non-linear, making it harder to trace bugs.
  2. Performance:

    • Poorly designed event handlers or excessive events can degrade performance.
  3. State Management:

    • Ensuring consistency across multiple event handlers requires careful planning.

Would you like more advanced examples or help applying event-driven programming in a specific context, like AR, gaming, or data pipelines? 🚀

01_Programming Paradigms

02_Object Oriented Programming

01_Programming Paradigms

03_Declarative Programming

01_Programming Paradigms

04_Functional Programming

Functional programming (FP) is a programming paradigm focused on writing software by composing and applying pure functions, avoiding shared state, and minimizing side effects. It's particularly well-suited for mathematical computations, data transformations, and scenarios requiring parallel processing.


Key Principles of Functional Programming

1. Pure Functions

Example:

# Pure function
def add(a, b):
    return a + b
result = 0

def add(a, b):
    global result
    result = a + b
    return result

Why It Matters:


2. Immutability

Example:

# Immutable transformation
numbers = [1, 2, 3]
new_numbers = [x * 2 for x in numbers]

Why It Matters:


3. Higher-Order Functions

Example:

# Map applies a function to each element
numbers = [1, 2, 3, 4]
squared = map(lambda x: x ** 2, numbers)
print(list(squared))  # Output: [1, 4, 9, 16]

Why It Matters:


4. First-Class Functions

Example:

def greet(name):
    return f"Hello, {name}!"

def execute(func, arg):
    return func(arg)

print(execute(greet, "Alice"))  # Output: "Hello, Alice!"

Why It Matters:


5. Recursion

Example (factorial with recursion):

def factorial(n):
    return 1 if n == 0 else n * factorial(n - 1)

print(factorial(5))  # Output: 120

Why It Matters:


6. Lazy Evaluation

Example:

# Lazy evaluation with a generator
def generate_numbers():
    for i in range(10):
        yield i

numbers = generate_numbers()
for num in numbers:
    print(num)  # Generates each number one at a time

Why It Matters:


7. Function Composition

Example:

def double(x):
    return x * 2

def square(x):
    return x ** 2

def compose(f, g):
    return lambda x: f(g(x))

double_then_square = compose(square, double)
print(double_then_square(3))  # Output: 36

Why It Matters:


Advantages of Functional Programming

  1. Predictable Code:

    • Pure functions ensure the output is consistent, making debugging easier.
  2. Concurrency and Parallelism:

    • No shared state or side effects mean functions can run independently.
  3. Modularity:

    • Encourages writing small, reusable functions that can be combined in powerful ways.
  4. Testability:

    • Pure functions are easy to test as they don’t depend on external states.
  5. Immutable Data:

    • Reduces bugs caused by unexpected changes to shared data.

Disadvantages of Functional Programming

  1. Learning Curve:

    • The paradigm requires a shift in thinking for those used to procedural or object-oriented programming.
  2. Performance:

    • Immutable data structures can sometimes lead to higher memory usage and slower performance compared to mutable ones.
  3. Debugging Recursion:

    • Heavy reliance on recursion can lead to stack overflow errors if not optimized (e.g., via tail recursion).
  4. Limited Libraries:

    • Some libraries or APIs are built with OOP in mind and may not work well with FP.

Functional Programming in Popular Languages

Functional-First Languages:

Functional Features in Multi-Paradigm Languages:

  1. Python:

    • Supports functional constructs like map, filter, lambda, and comprehensions.
    • Example:
      nums = [1, 2, 3, 4]
      squares = list(map(lambda x: x ** 2, nums))
      print(squares)  # Output: [1, 4, 9, 16]
      
  2. JavaScript:

    • Functional tools like reduce, map, and filter.
    • Example:
      const nums = [1, 2, 3, 4];
      const squares = nums.map(x => x ** 2);
      console.log(squares);  // Output: [1, 4, 9, 16]
      
  3. C++:

    • Lambdas and standard functional algorithms in the STL (std::transform, std::accumulate).
    • Example:
      #include <vector>
      #include <algorithm>
      #include <iostream>
      
      int main() {
          std::vector<int> nums = {1, 2, 3, 4};
          std::transform(nums.begin(), nums.end(), nums.begin(), [](int x) { return x * x; });
          for (int n : nums) std::cout << n << " ";  // Output: 1 4 9 16
      }
      

Applications of Functional Programming

  1. Graphics Programming:

    • Procedural texture generation and transformations (e.g., GLSL shaders).
    • Functional paradigms simplify operations on immutable data like pixels or vertex buffers.
  2. Data Processing:

    • Big data frameworks like Apache Spark rely on FP for parallelism and immutability.
  3. Game Development:

    • Functional constructs help build procedural systems like terrain generation or AI logic.
  4. Concurrency:

    • Functional programming is ideal for writing highly concurrent and parallel systems due to immutability.

Would you like more hands-on examples in Python or another language, or a deeper dive into functional constructs? 🚀

PYQT

As a Technical Artist, questions related to PyQt during an interview will likely focus on how well you understand creating GUI tools for artists or pipelines in the animation, gaming, or VFX industries. These questions can span conceptual understanding, practical implementation, and problem-solving with PyQt. Here are the common areas and examples of questions you might encounter:


1. General PyQt Basics

Questions:

  1. What is PyQt, and how is it used in production pipelines?

    • Explanation: PyQt is a Python binding for Qt, widely used for building cross-platform GUIs, often for in-house tools in the VFX or gaming industries.
    • Example Use Case: A custom shader editor for artists.
  2. What are the main differences between PyQt and PySide?

    • Topics: Licensing, API compatibility, or use cases.
  3. Explain the structure of a PyQt application.

    • Expected to describe components like QApplication, QMainWindow, QWidget, and signals/slots.

Hands-On Questions:


2. Signals and Slots

Questions:

  1. What are signals and slots in PyQt? How do they work?

    • Explanation: Signals are emitted by PyQt widgets to indicate a change, and slots are functions connected to these signals.
  2. How would you connect a custom signal to a custom slot?

    • Topics: Creating custom signals using pyqtSignal and connecting them to a slot.

Hands-On Questions:


3. Layouts and Widgets

Questions:

  1. How do you manage layouts in PyQt?

    • Topics: Understanding QVBoxLayout, QHBoxLayout, QGridLayout, and their hierarchical relationships.
  2. What is the difference between QWidget and QMainWindow?

    • Explanation: QMainWindow provides predefined layout areas (menu bar, toolbars), while QWidget is a more general-purpose container.

Hands-On Questions:


4. Advanced PyQt Topics

Questions:

  1. How do you implement drag-and-drop functionality in PyQt?

    • Topics: Overriding event handlers like dragEnterEvent, dragMoveEvent, and dropEvent.
  2. How do you use QThreads in PyQt for long-running operations?

    • Explanation: Demonstrate knowledge of multithreading and how to update the GUI without freezing.
  3. How would you integrate PyQt with another Python library (e.g., OpenGL or PySide)?

    • Topics: Custom rendering or combining PyQt with tools like numpy or matplotlib.

Hands-On Questions:


5. Styling and Customization

Questions:

  1. How do you style widgets in PyQt?

    • Explanation: Use QStyle, QPalette, or CSS-like setStyleSheet.
  2. How can you create custom widgets in PyQt?

    • Topics: Subclassing QWidget and implementing custom painting or behavior.

Hands-On Questions:


6. Integration with Pipelines

Questions:

  1. How would you use PyQt to integrate tools into a DCC application (e.g., Maya, Blender, or Houdini)?

    • Explanation: Embedding PyQt UIs within a larger software context.
  2. How do you communicate between PyQt and a backend script or API?

    • Topics: Using Python APIs (like REST or RPC) to fetch or send data dynamically.

Hands-On Questions:


7. Performance Optimization

Questions:

  1. What are some common pitfalls in PyQt applications?

    • Explanation: Blocking the GUI thread, poor memory management, or slow rendering.
  2. How do you optimize a PyQt application for large data sets?

    • Topics: Virtualized views (QTableView or QListView) and lazy loading.

Hands-On Questions:


Example Problem

"Build a Texture Manager GUI in PyQt"


What Interviewers May Be Evaluating

  1. Your Understanding of PyQt Basics: Signals/slots, widgets, layouts, and event handling.
  2. Problem-Solving Skills: Ability to design and implement GUI solutions for real-world scenarios.
  3. Code Modularity and Reusability: Creating scalable and maintainable GUI code.
  4. Integration and Optimization: Embedding PyQt tools into DCC applications or pipelines and handling performance challenges.

Mastering these areas will prepare you for most PyQt-related questions a technical artist might encounter. Let me know if you'd like help with specific implementations!

USD

Blender

Questions

Training Datasets

cmake

File Handling

🗂️ Python File Handling — Q & A (with code)


Q1: How do you read a file line-by-line safely in Python?

A:

with open('data.txt', 'r') as f:
    for line in f:
        print(line.strip())

Q2: How do you write a list of lines to a file in Python?

A:

lines = ['one\n', 'two\n', 'three\n']
with open('output.txt', 'w') as f:
    f.writelines(lines)

Q3: How do you check if a file exists before opening it?

A:

import os
if os.path.exists('file.txt'):
    with open('file.txt') as f:
        print(f.read())

Q4: How do you list all files in a folder with a .txt extension?

A:

import os
files = [f for f in os.listdir('my_folder') if f.endswith('.txt')]
print(files)

Q5: How do you recursively list all .jpg files in a directory and its subdirectories?

A:

import os
jpgs = []
for root, dirs, files in os.walk('assets'):
    for f in files:
        if f.endswith('.jpg'):
            jpgs.append(os.path.join(root, f))

Q6: How do you create a folder if it doesn’t exist?

A:

import os
os.makedirs('my_folder', exist_ok=True)

Q7: How do you read and write JSON data using Python?

A:

import json

# Writing
data = {'name': 'Alice', 'age': 30}
with open('data.json', 'w') as f:
    json.dump(data, f, indent=4)

# Reading
with open('data.json') as f:
    loaded = json.load(f)

Q8: How do you move or rename a file?

A:

import shutil
shutil.move('old_name.txt', 'new_folder/new_name.txt')

Q9: How do you delete a file safely in Python?

A:

import os
if os.path.exists('to_delete.txt'):
    os.remove('to_delete.txt')

Q10: How do you get the filename and extension separately?

A:

import os
path = '/path/to/file.jpg'
name, ext = os.path.splitext(os.path.basename(path))
print(name)  # file
print(ext)   # .jpg

Ready for me to export this as a .csv for Anki?