TouchDesigner 里面的Python (python  in Touchdesigner)

TouchDesigner 里面的Python (python in Touchdesigner)

TouchDesigner 中使用 Python 的打印(print)基础

针对初学者介绍了在 TouchDesigner 文本端口(Textport)中使用 Python 打印输出的核心概念与常见操作。文档以示例代码与概念解释相结合,便于教学使用。


1. 打开 Textport 并运行脚本

在 TouchDesigner 界面,通过右上角的下拉菜单打开 Textport。在 Textport 中输入脚本,右键点击并选择 Run Script 执行,输出将显示在 Textport 窗口中。


2. 基本的 print() 用法

# 单引号与双引号等价,但必须配对
print('hello world')
print("hello world")
  • 功能:在控制台输出字符串。
  • 注意:引号必须匹配,否则会报语法错误。

3. 数据类型与打印

Python 中常见的数据类型及打印方式:

# 字符串(string)
print("这是一个字符串")

# 整数(integer)
print(42)

# 浮点数(float)
print(3.14)

# 布尔值(boolean)
print(True)
print(False)
  • 字符串:一系列字母、数字和符号,需用引号包裹。
  • 整数:不带小数点的数字。
  • 浮点数:包含小数点的数字。
  • 布尔值TrueFalse,在数学运算中会自动转换为 10

4. 变量定义与打印

将数据赋给变量后再打印:

text = "TouchDesigner"
print(text)

num = 2
print(num * 2)   # 整数相乘,输出 4

flt = 2.5
print(flt * 2)   # 浮点数相乘,输出 5.0

flag = False
print(flag)      # 输出 False
print(flag * 2)  # False 在运算中等同于 0,输出 0
  • 变量:通过 变量名 = 值 声明。
  • 操作:数值类型可参与算术运算;字符串相加实现拼接。

5. 多行字符串与输出换行

5.1 使用转义字符 \n

print("第一行\n第二行\n第三行")
  • \n 表示换行符。

5.2 三引号定义多行字符串

text = """第一行
第二行
第三行"""
print(text)
  • 三引号('''""")可定义跨多行的字符串,便于阅读和维护。

6. 字符串格式化与占位符

6.1 基础占位符 %s, %d, %r

template = "你好,%s!今天有 %d 只猫。"
name = "Alice"
count = 3
print(template % (name, count))
  • %s:字符串占位;
  • %d:整数占位;
  • %r:任意类型的原始表示。

6.2 传入多个参数

text = "您有 %s 猫,颜色是 %s,体重 %.1f kg。"
print(text % ("两只", "黑色", 4.5))
  • 参数需按顺序放入元组,类型需与占位符对应或使用 %r

7. 数值与字符串混合打印

7.1 使用逗号分隔

name = "Count"
value = 10
print(name, value)  # 输出:Count 10,中间自动添加空格,且不计算运算

7.2 显式转换

print("Count is " + str(value))  # 将整数转为字符串后拼接

8. 常见调试场景

  • 检查变量值:在脚本中多处插入 print(var),快速了解运行状态。
  • 运行顺序:Python 按照脚本从上至下执行,先定义变量再使用。
  • 数据类型误用:布尔、数值与字符串混用时需注意自动转换与报错情况。

9. 小结

  • print() 是最简单有效的调试工具,能实时在 Textport 查看变量与执行结果。
  • 掌握不同数据类型的打印方式、格式化占位符和多行字符串定义,能够编写清晰易读的脚本。
  • 在 TouchDesigner 中结合 Python 脚本,可实现丰富的可视化与数据处理任务。
    ^1

TouchDesigner 中使用 Python 的变量(Variables)详解


1. 变量的定义与概念

变量(Variable) 是用于存储和重用数据的“容器”,可随时取回并参与运算或引用。

# 定义整数类型变量
red_marbles   = 10    # 红色弹珠数量
blue_marbles  = 5     # 蓝色弹珠数量
green_cat_eyes= 6     # 绿“猫眼”弹珠数量
blue_cat_eyes = 12    # 蓝“猫眼”弹珠数量
  • 等号左侧为 变量名,右侧为
  • 变量名应具可读性、避免空格及特殊字符。

2. 变量运算与求和

将各类弹珠总数累加为总库存:

total_marbles = red_marbles + blue_marbles + green_cat_eyes + blue_cat_eyes
  • 不同数值变量可直接相加,结果赋予新变量 total_marbles

3. 打印带占位符的字符串

在打印时使用 %d%s 等占位符,将变量嵌入文本中:

# 模板字符串中,%d 表示整数占位
template = "库存:红色 %d,蓝色 %d,绿猫眼 %d,蓝猫眼 %d,总计 %d"
print(template % (red_marbles, blue_marbles, green_cat_eyes, blue_cat_eyes, total_marbles))
  • % 后跟元组,顺序对应所有占位符。
  • 可追加分隔线,增强可读性:
print("-" * 40)    # 输出 40 个连字符

4. 从 Table DAT 读取变量

在 TouchDesigner 中,弹珠数量也可存储于 Table DAT 单元格,通过 Python 引用:

# 假设已有名为 table_marbles 的 Table DAT,4 行 2 列
# 单元格格式:第一列为名称,第二列为数量
red_marbles    = op('table_marbles')[0, 1]   # 第一行、第二列
blue_marbles   = op('table_marbles')[1, 1]
green_cat_eyes = op('table_marbles')[2, 1]
blue_cat_eyes  = op('table_marbles')[3, 1]
  • op('table_marbles') 获取 Table DAT 操作符引用。
  • [row, col] 指定行列索引(从 0 开始)。

5. 操作节点参数的变量引用

可将常用操作符(Operator)与其参数通过变量简化多次调用:

# 引用名为 level1 的 Level TOP
lvl = op('level1')

# 直接修改参数
lvl.par.opacity = 0.0
lvl.par.invert  = 0.31
lvl.par.blacklevel = 0.27
# …以此类推
  • op('level1') 获取节点,保存在变量 lvl 中;
  • .par.参数名 访问并修改对应参数。

6. 批量修改参数的优化

对于多个参数的连续修改,可先将节点引用存入变量,再依次调用,减少重复 op()

lvl = op('level1')  # 只调用一次 op()

lvl.par.opacity     = 0.78
lvl.par.invert      = 0.31
lvl.par.blacklevel  = 0.27
lvl.par.brightness1 = 1.45
lvl.par.gamma1      = 0.50
lvl.par.contrast    = 1.76
  • 变量复用提高脚本简洁性与可维护性。

7. 结合 Table DAT 批量应用预设

假设有一个名为 presets 的 Table DAT,包含多行预设参数,可动态读取并赋值:

preset_table = op('presets')  # Table DAT
preset_index = 1              # 当前预设行(从 0 开始)

# 从表头获取参数名称,援引至 Level TOP
lvl = op('level1')
param_names = ['invert', 'blacklevel', 'brightness1', 'gamma1', 'contrast', 'opacity']

for col, pname in enumerate(param_names):
    value = preset_table[preset_index, col+1]  # 列 +1 跳过名称列
    setattr(lvl.par, pname, value)             # 动态赋值
  • preset_index 可由 UI 常数或 CHOP 通道控制,动态切换预设行;
  • setattr(object, name, value) 根据字符串 name 设置属性。

8. 结合常数(Constant CHOP)动态切换行号

可使用 Constant CHOP 的输出通道值作为 preset_index,并将其转换为整数:

# 读取 Constant CHOP 输出
const_chop = op('constant1')
idx_float = const_chop['chan1'].eval()     # 通道值(浮点)
preset_index = int(idx_float)              # 转为整数

# 按上例循环应用预设
  • .eval() 获取当前通道数值;
  • int() 将浮点数转整,与行号匹配。

小结

  1. 变量 用于存储数据与引用节点,简化代码与提升可维护性。
  2. 占位符格式化字符串拼接 结合变量,便于输出动态信息。
  3. Table DATOperator.par 的变量引用,使数据与节点参数互通。
  4. 常数 CHOP 或 UI 控件值转为整数,即可动态切换数据行或预设。

掌握以上模式,便可在 TouchDesigner 中编写结构清晰、复用性高的 Python 脚本,快速对数据与节点进行联动与自动化控制。
^1

TouchDesigner 中的 Python 引用(References)详解


1. 基本语法:op() 与索引/名称引用

  • 引用 Operator
# 通过名称获取 Operator 引用
lfo = op('lfo1')    
# 获取该 Operator 的第一个通道(名称引用)
value = lfo[‘chan1’]  
# 或通过通道索引(位置引用,0 开始)
value = lfo[^0]        
- `op('名称')`:返回指定名称的 Operator。
- `[...]`:方括号内可填通道名称(字符串)或通道索引(整数)。
  • 引用 TOP 参数
circle = op('circle1')
# 将 LFO 通道驱动 circle 的 center X
circle.par.centerx = op('lfo1')['chan1']

2. 反向与组合运算

  • 取相反值
val = op('lfo1')[^0]
circle.par.centery = -val  # 反向移动
  • 对角线运动
x = op('lfo1')[^0]
y = op('lfo1')[^0]
circle.par.centerx, circle.par.centery = x, y

3. 利用 CHOP/Constant CHOP 驱动表达式

  • Constant CHOP + Speed CHOP
rate_ch = op('constant1')['chan1']  # 固定速率
timer = op('speed1')['chan1']      
# speed1 根据 rate_ch 持续累加
  • 结合三角函数绘制圆环
import math
r = 0.4
t = op('speed1')[^0]
circle.par.centerx = math.cos(t) * r
circle.par.centery = math.sin(t) * r
  • 绘制椭圆
r1 = 0.4; r2 = 0.2
circle.par.centerx = math.cos(t) * r1
circle.par.centery = math.sin(t) * r2

4. 从 Table DAT 中读取参数

tbl = op('table1')  
# 2×2 表:行 0→radius1, 行 1→radius2;列 0→名称、列 1→数值
r1 = tbl[0,1]  
r2 = tbl[1,1]
  • [row, col] 指定行列索引。
  • 也可用表头名称:tbl['radius1', 1]

5. 文件与路径引用示例

  • 引用 Samples 目录
import os
path = app.samplesFolder + '/map/planet.f4v'
movie = op('moviefilein1')
movie.par.file = path
  • 从 Folder DAT 获取路径
fld = op('folder1')
# 第三行、第二列(列索引 1)路径
movie.par.file = fld[2,1]

6. 阅读 Python Help 文档

  1. 在 Parameter 界面点击小问号,打开 Class Help。
  2. 理解 Members(成员)与 Methods(方法):
    • TOP 类成员:widthheightaspect 等。
    • Operator 类成员:namedigitscookTime 等。
  3. 在 Textport 中测试表达式:
op('moviefilein1').fileHeight  # 返回视频高度(像素)
op('moviefilein1').fileWidth   # 返回视频宽度(像素)
  1. 若出现 NameError,表明忘记加引号或变量未定义,需补全字符串或变量声明。

小结

  • 使用 op('name') 获取 Operator 引用,并通过索引或名称访问其 Channel、DAT、参数等。
  • 结合数学模块,可在表达式中绘制圆形、椭圆等复杂运动轨迹。
  • 从 Table DAT、Folder DAT 等数据表中动态获取数值与路径。
  • 掌握阅读 Python Help 文档,快速查找合适的成员与方法,拓展脚本功能。

通过上述技巧,能够在 TouchDesigner 中编写清晰、动态、可扩展的 Python 表达式,实现复杂的数据联动与可视化控制。
^1

TouchDesigner 中的 Python 逻辑基础(Logic – Part 1)

概览

在 TouchDesigner 脚本中,逻辑(Logic) 用于根据条件执行不同操作。常见构造包括:

  • ifelifelse
  • 比较运算符:><>=<===!=
  • 逻辑运算符:andor
  • 取模运算符:%

以下示例均在 Text DAT 中编辑,配合 外部文本编辑器(如 Sublime)更易编写和调试。


1. 基本的 if…else 语句

# 定义变量
my_int = 5

# 简单打印
print("my_int is %d" % my_int)

# 基本 if…else
if my_int >= 6:
    print("This number is greater than or equal to 6")
else:
    print("This number is less than 6")
  • if 后跟条件表达式,末尾须加冒号 :
  • 条件成立时执行缩进块,否则执行 else
  • pass 可用于空操作,保持语法完整:
if my_int >= 6:
    pass  # 条件成立时不做任何事
else:
    print("Number is less than 6")

2. elif 多分支测试

my_int = 6

if my_int > 6:
    print("This number is greater than 6")
elif my_int == 6:
    print("This number is exactly 6")
else:
    print("This number is less than 6")
  • elif(else if)可添加额外条件,避免多层嵌套
  • 建议每个 if 块都配对 else,确保所有情况均被覆盖

3. 不等于运算:!=

if my_int != 6:
    print("This number is not 6")
else:
    print("This number is 6")
  • != 表示“不等于”,是比较运算符之一

4. 嵌套 if:测试奇偶

my_int = 8

if my_int >= 6:
    print(">=6:", my_int)
    # 测试奇偶:用 modulus (%) 判断余数
    if my_int % 2 == 0:
        print("Even number")
    else:
        print("Odd number")
else:
    print("<6:", my_int)
  • % 运算符返回除法余数
  • my_int % 2 == 0,则为偶数,否则为奇数

5. 同时测试多个条件:and

my_int = 7

# 测试范围:同时检查两端
if my_int > 4 and my_int < 10:
    print("%d is between 4 and 10" % my_int)
else:
    print("%d is <=4 or >=10" % my_int)
  • and 要求左右两个条件都为真,整体才为真

6. 同或测试:or

my_int = -5

# 测试大于 4 或等于 -5
if my_int > 4 or my_int == -5:
    print("%d is >4 or ==-5" % my_int)
else:
    print("%d is <=4 and !=-5" % my_int)
  • or 任一条件为真即执行分支

7. 用变量降低硬编码

将测试值抽为变量,简化后续修改:

test_val = 4
my_int   = 7

if my_int > test_val:
    print("%d is greater than %d" % (my_int, test_val))
else:
    print("%d is less than or equal to %d" % (my_int, test_val))
  • 将常用数字或比较值放在顶部,便于统一管理

小结

  • if/elif/else:构建分支逻辑
  • 比较运算符>, <, >=, <=, ==, !=
  • 逻辑运算符and, or
  • 取模运算% 用于判断奇偶或循环余数
  • 变量管理:抽象常量,减少硬编码

掌握以上逻辑构造后,可在 TouchDesigner Python 脚本中实现复杂的条件判断与分支控制,为后续网络中的交互和自动化提供强大支持。
^1

TouchDesigner 中的 Python 逻辑进阶(Logic – Part 2)

在 Part 1 中学习了基本的逻辑分支与比较运算,本章聚焦于在 TouchDesigner 中使用 References(引用)将 CHOP 通道作为对象,动态读取与比较其值,并探索 Channel Class 的成员属性。


1. 从 Constant CHOP 读取通道值

# 假设网络中已有 Constant CHOP:constant1 和 constant2
# 并将其两个通道分别命名为 chan1、chan2

# 将通道值当作浮点数读取
val1 = float(op('constant1')['chan1'].eval())
val2 = float(op('constant1')['chan2'].eval())
val3 = float(op('constant2')['chan1'].eval())
val4 = float(op('constant2')['chan2'].eval())

# 打印以验证
print("val1 =", val1)
print("val2 =", val2)
print("val3 =", val3)
print("val4 =", val4)
  • op('constant1')['chan1'] 返回 Channel 对象
  • .eval() 得到通道当前数值
  • float(...) 转为浮点数,避免 %d 只显示整数

2. 比较两个 CHOP 通道

# 定义比较函数,传入两组值及描述
def compare(name1, v1, name2, v2):
    if v1 == v2:
        print(f"{name1} == {name2}")
    elif v1 > v2:
        print(f"{name1} > {name2}")
    else:
        print(f"{name1} < {name2}")

# 调用比较
compare("chan1@const1", val1, "chan1@const2", val3)
compare("chan2@const1", val2, "chan2@const2", val4)
  • 三分支判断相等、大于、小于
  • 函数封装减少重复代码

3. 利用 Channel Class 读取元信息

Channel 对象拥有丰富成员,可获取索引、名称、所属 Operator 等属性:

ch = op('constant1')['chan1']  # Channel 对象

idx   = ch.index     # 通道索引(位置)
name  = ch.name      # 通道名字(字符串)
owner = ch.owner     # 所属 Operator 对象

print("Index:", idx)
print("Name :", name)
print("Owner:", owner.path)  # 输出 Operator 路径
  • .index.name.owner 均为成员属性
  • 在脚本中可根据需要访问其他成员,如 .vals.sampleRate

4. 综合示例:基于引用的动态比较

# 读取两组通道
c1 = op('constant1')
c2 = op('constant2')
v1 = c1['chan1'].eval()
v2 = c2['chan1'].eval()

# 获取 Channel 对象,用于读取元信息
ch1 = c1['chan1']
ch2 = c2['chan1']

# 定义带元信息的比较
if v1 == v2:
    print(f"{ch1.owner.name}.{ch1.name} == {ch2.owner.name}.{ch2.name}")
elif v1 > v2:
    print(f"{ch1.owner.name}.{ch1.name} > {ch2.owner.name}.{ch2.name}")
else:
    print(f"{ch1.owner.name}.{ch1.name} < {ch2.owner.name}.{ch2.name}")
  • 动态引用 Operator 与通道名称,输出格式如 constant1.chan1 > constant2.chan1
  • 更具可读性,网络名称即作文中描述

5. 小结

  1. 动态引用 CHOP:通过 op(…)[…] 获取 Channel 对象,.eval() 得到值。
  2. 类型转换:将通道数值转为浮点数,避免整数格式化丢失小数。
  3. 封装比较:使用函数或分支逻辑组织代码,提升可维护性。
  4. Channel Class:访问 .index.name.owner 等属性,获取通道元信息。

掌握以上模式后,便可在 TouchDesigner 中编写更加灵活、动态且易扩展的 Python 脚本,实现控件驱动逻辑、数据监测与自动化控制。
^1

Python 列表(Lists)基础

TouchDesigner 中可通过 Python 列表管理任意数量和类型的数据。本节介绍列表的定义、索引、切片、动态添加与嵌套用法。


1. 列表概念

# 列表:一系列有序元素,使用方括号 [] 包裹,元素间以逗号分隔
kitties = ['Maddy', 'Reagan', 'Kitty']  # 字符串列表
numbers = [1, 2, 3, 4, 5]               # 整数列表
mixed = ['eggs', 3.14, True, 42]        # 混合类型列表
  • 列表可包含任意类型,甚至嵌套列表
  • 列表长度可动态变化

2. 访问单个元素(索引)

grocery = ['eggs', 'milk', 'bread', 'butter', 'coffee']

print(grocery[^0])  # 输出 'eggs',索引从 0 开始
print(grocery[^4])  # 输出 'coffee'
  • 索引超出范围会报 IndexError

3. 切片(Slicing)

print(grocery[:3])   # 前 3 个元素 ['eggs','milk','bread']
print(grocery[2:])   # 从索引 2 到末尾 ['bread','butter','coffee']
print(grocery[-2:])  # 最后 2 个元素 ['butter','coffee']
  • list[start:end]:包含 start,不含 end
  • 省略 startend 分别表示从头或到尾
  • 负索引从末尾开始计算(-1 表示最后一个元素)

4. 列表长度

print(len(grocery))  # 输出 5
  • len() 返回元素个数

5. 动态添加元素

lst = []            # 空列表

lst.append('apple')          # 在末尾添加单个元素
lst.extend(['kiwi', 10, True])  # 在末尾追加另一个列表所有元素

print(lst)  # ['apple','kiwi',10,True]
  • append(x):添加单个元素
  • extend(iterable):添加可迭代对象所有元素

6. 嵌套列表(列表的列表)

# 超市部门及库存
store = [
    ['Fruit',       ['apple','kiwi','orange']],
    ['Baked Goods', ['bread','pie','muffin']],
    ['Drinks',      ['cola','sprite','root beer']],
]

# 访问“Fruit”部门列表
print(store[^0])         # ['Fruit',['apple',...]]
print(store[^0][^0])      # 'Fruit'            # 部门名称
print(store[^0][^1])      # ['apple','kiwi','orange']  # 库存列表

# 访问“Fruit”库存第 2 项
print(store[^0][^1][^1])   # 'kiwi'
  • store[行][列] 对应二维坐标
  • 可随层级继续嵌套(不建议过深)

7. 小结

  • 定义lst = [a, b, c]
  • 索引lst[i] 获取单个元素
  • 切片lst[start:end] 批量获取子序列
  • 长度len(lst)
  • 添加append()extend()
  • 嵌套lst = [[...],[...]] 用方括号实现多层列表

掌握以上操作,即可在 TouchDesigner 脚本中灵活管理多种数据集。

TouchDesigner 中的 Python 列表进阶应用

本节示例演示如何将 TouchDesigner 的 CHOP、SOP 和 COMP 元素视作 Python 列表,利用列表操作简化数据读取与批量控制。


1. 将 Noise CHOP 通道当作列表

# 引用 Noise CHOP,采样点数设为 10
noise1 = op('noise1')

# 读取所有样本为列表
samples = noise1['chan1'].vals   # .vals 返回 Python 列表

print("Samples:", samples)
print("First sample:", samples[^0])
print("Number of samples:", noise1.numSamples)  # 等价于 len(samples)
  • .vals 属性提供通道值列表
  • .numSamples 直接返回样本数,无需使用 len()

2. 将 SOP 的点(Points)当作列表

# 引用 Rectangle SOP
rect = op('rectangle1')

# Points 属性为 Point 对象列表
pts = rect.points  

# 访问第一个 Point
p0 = pts[^0]
print("Point 0:", p0)

# 读取该 Point 的位置坐标
pos = p0.P  # [.P] 返回三元组坐标 (x,y,z)
print("Position:", pos)
  • comp.points 返回 Point 对象列表
  • 可使用索引与切片操作遍历或提取子集

3. 利用 COMP.findChildren() 返回子组件列表

# 引用 Container COMP,其中包含若干 Button COMP
ctr = op('container1')

# 查找深度为 1 且类型为 'button' 的子 OP
buttons = ctr.findChildren(type=buttonCOMP, depth=1)

# 输出所有按钮的名字
for b in buttons:
    print("Found button:", b.name)

# 激活第一个按钮(模拟点击)
buttons[^0].click()
  • findChildren(type=…, depth=…) 返回符合条件的 Operator 列表
  • 对该列表可进行索引、循环、方法调用(如 .click()

4. 列表与脚本交互示例

# 以 Noise CHOP 样本为驱动,改变多个 Rectangle 的位置
noise = op('noise1')['chan1'].vals
rects = op('geo1').findChildren(type=rectangleCOMP, depth=1)

# 保证样本数 >= 矩形数
count = min(len(noise), len(rects))

for i in range(count):
    # 使用样本值平移每个矩形的 Y 坐标
    rects[i].par.ty = noise[i]
  • 将 CHOP 列表与 COMP 子列表一一映射
  • 通过循环结合列表索引,批量修改节点参数

小结

  • .vals.points.findChildren() 等成员返回 Python 列表或类似列表的集合。
  • 利用列表索引、切片、迭代,可灵活访问、过滤与批量处理 OP、CHOP、SOP 数据。
  • 掌握列表概念后,结合循环与条件判断,可在 TouchDesigner 中实现强大自动化与交互逻辑。
    ^1

Python 字典(Dictionaries)基础

在 TouchDesigner 中,字典是一种以 键–值(key–value)对存储数据的结构,适用于按名称快速查找。相比列表按索引访问,字典可直接通过键获取对应值,更加直观。


1. 字典定义与语法

# 定义一个简单字典:键和值均为字符串或数字等
grocery = {
    'eggs'  : 12,      # 键 'eggs' 对应值 12(打)
    'milk'  : 1.0,     # 键 'milk' 对应值 1.0(夸脱)
    'butter': 1,       # 键 'butter' 对应值 1(磅)
    'coffee': 2        # 键 'coffee' 对应值 2(磅)
}
  • 使用 大括号 {} 定义字典
  • 每个条目为 键:值,条目间以逗号分隔
  • 键(key)通常为字符串,值(value)可为任意类型

2. 通过键访问值

# 读取单项库存
print("Eggs   :", grocery['eggs'])    # 输出 12
print("Coffee :", grocery['coffee'])  # 输出 2
  • 访问不存在的键将引发 KeyError

3. 遍历所有键、值或键–值对

# 遍历所有键
for item in grocery.keys():
    print("Item:", item)

# 遍历所有值
for qty in grocery.values():
    print("Qty :", qty)

# 遍历键–值对
for item, qty in grocery.items():
    print(f"{item} -> {qty}")
  • .keys().values().items() 返回视图对象,可用于循环

4. 动态添加与更新

inv = {}  # 空字典

# 添加或更新条目
inv['apple']  = {'qty':12, 'origin':'VT', 'organic':True}
inv['orange'] = {'qty':10, 'origin':'CA', 'organic':False}

# 修改已存在键对应值
inv['apple']['qty'] = 8  
  • 直接通过 dict[key] = value 添加或更新
  • 值可嵌套列表或其他字典

5. 嵌套字典示例

# 多级字典:库存信息
inventory = {
    'apple':  {'qty':12, 'origin':'VT', 'organic':True},
    'orange': {'qty':10, 'origin':'FL', 'organic':False},
    'grapes': {'qty':50, 'origin':'CA', 'organic':True}
}

# 访问“apple”库存的所有字段
apple_info = inventory['apple']
print("Apple Info:", apple_info)

# 读取单个字段
print("Apple Qty   :", inventory['apple']['qty'])
print("Apple Origin:", inventory['apple']['origin'])
print("Apple Organic:", inventory['apple']['organic'])
  • 字典值可为其他字典,实现多级数据结构

6. 格式化输出示例

for item, info in inventory.items():
    print(f"{item.title()}: {info['qty']} units from {info['origin']}, organic={info['organic']}")
  • 使用 Python 3 的 f-string 插入字典值
  • .title() 使键名首字母大写

小结

  • 字典通过 快速定位对应 ,适合无序数据存取。
  • 使用 .keys().values().items() 可遍历字典内容。
  • 支持动态添加、更新与嵌套,实现灵活数据组织。
  • 在 TouchDesigner 脚本中,可用以管理多维参数、组件属性及自定义数据。
    ^1

TouchDesigner 中使用 字典(Dictionaries)管理预设

在 TouchDesigner 中,可利用 Python 字典将 UI 组件或节点参数的预设保存为“键–值”映射,通过脚本快速应用、切换多种配置。


1. 准备环境

  • 在网络中放置一个 Text DAT(脚本容器)和一个或多个带大量参数的 OP(如 Text TOP、Level TOP)。
  • 确保 Text DAT 编辑器已切换至外部编辑器(如 Sublime),便于多行缩进与对齐。

2. 定义“预设字典”

# 保存 Text TOP 多参数预设
text_presets = {
    'preset1': {           # 预设 1
        'text'      : 'Hello',
        'fontsize'  : 20,
        'alignx'    : 1,   # 1=center
        'aligny'    : 1,
        'fontcolorr': 1.0, # 红色通道
        'fontcolorg': 0.0,
        'fontcolorb': 0.0,
        'fontalpha' : 1.0,
        'bgcolorr'  : 0.0,
        'bgcolorg'  : 0.0,
        'bgcolorb'  : 0.0,
        'bgalpha'   : 0.5,
    },
    'preset2': {           # 预设 2
        'text'      : 'Monkey',
        'fontsize'  : 15,
        'alignx'    : 0,   # 0=left
        'aligny'    : 1,
        'fontcolorr': 0.0,
        'fontcolorg': 1.0,
        'fontcolorb': 0.0,
        'fontalpha' : 0.8,
        'bgcolorr'  : 0.0,
        'bgcolorg'  : 0.0,
        'bgcolorb'  : 0.0,
        'bgalpha'   : 1.0,
    }
}
  • :预设名称(preset1preset2
  • :另一个字典,保存对应 OP 各参数的 键–值

3. 应用预设

# 目标 Text TOP
txt = op('text1')

# 选定要应用的预设
preset_key = 'preset1'       # 可动态修改

# 获取对应参数字典
cfg = text_presets[preset_key]

# 遍历字典,按键调用 OP.par.<参数名>
for key, val in cfg.items():
    setattr(txt.par, key, val)
  • text_presets[preset_key] 返回所选预设的参数字典
  • setattr(txt.par, key, val) 动态赋值,等同于 txt.par.text = 'Hello'

4. 扩展:多个 OP 与多级字典

可将多种 OP 预设整合在同一字典中,或对单一 OP 的更多层级结构:

# 全局预设字典,包含多个 COMP
presets = {
    'preset1': {
        'text1': { 'text':'Hi','fontsize':12 },
        'level1': { 'brightness1':1.2, 'opacity':0.8 }
    },
    'preset2': {
        'text1': { 'text':'Welcome','fontsize':18 },
        'level1': { 'brightness1':0.5, 'opacity':1.0 }
    }
}

# 应用
key = 'preset2'
for compName, cfg in presets[key].items():
    comp = op(compName)
    for param, val in cfg.items():
        setattr(comp.par, param, val)
  • 外层字典按预设分组,内层字典分 OP,最内层字典分参数
  • 双重循环批量设置多个节点的多个参数

小结

  • 将多个参数分组存储于字典,可灵活管理多套预设。
  • 通过脚本动态选择键并遍历赋值,实现一行代码切换所有配置。
  • 嵌套字典支持多节点、多参数的批量控制,为 TouchDesigner 自动化与交互提供强大支持。
    ^1

TouchDesigner 中的 Python 函数(Functions)入门


1. 函数概念

  • 函数:一段可重复调用的代码块,用于执行单一功能,提高模块化与复用性。
  • 语法结构:
def 函数名(参数列表):
    """可选文档注释(docstring)"""
    函数体
    return 返回值

2. 定义与调用

# 定义函数
def say_hello():
    print("Hello, TouchDesigner!")  # 在函数内部打印
    return  # 可省略

# 调用函数
say_hello()  # 输出 "Hello, TouchDesigner!"
  • def 开头,后跟函数名与空括号
  • 冒号 : 表示函数体开始,体内需缩进
  • 调用时写 函数名() 即可执行

3. 返回值(return)

# 返回字符串
def get_greeting():
    text = "Hello, World!"
    return text  # 返回 text

# 调用并接收
g = get_greeting()
print(g)  # 输出 "Hello, World!"
  • return 将值传出函数,调用处才能获取
  • 不使用 print,可在外部决定如何显示或处理返回值

4. 带参数的函数

# 将整数转换为小数
def to_decimal(val):
    return val / 100.0

# 调用并打印结果
print(to_decimal(40))  # 输出 0.4
  • 括号内定义参数名,如 val
  • 调用时传入对应实参,如 to_decimal(40)

5. 多参数与多返回值

# 计算小费与账单总额
def tip_calculator(total, tip_pct):
    tip    = total * tip_pct / 100
    bill   = total + tip
    return tip, bill  # 返回元组

# 调用并接收两个返回值
t, b = tip_calculator(50, 15)
print("Tip:", t)  # 7.5
print("Bill:", b) # 57.5
  • 支持多个参数:def f(a, b):
  • return x, y 返回多个值,接收时用元组解包

6. 将函数组合与分离职责

# 计算并返回 (tip, bill)
def calc_tip(total, pct):
    tip  = total * pct / 100
    bill = total + tip
    return tip, bill

# 美化输出
def display_bill(data):
    tip, bill = data
    line = "-" * 30
    print(line)
    print(f"Tip  : {tip:.2f}")
    print(f"Total: {bill:.2f}")
    print(line)

# 主流程
result = calc_tip(100, 20)
display_bill(result)
  • calc_tip 专注计算
  • display_bill 专注格式化输出
  • 职责分离,提高可维护性与复用性

小结

  1. 使用 def 定义函数,函数体需缩进。
  2. return 将值返回,调用处可捕获。
  3. 参数与返回值支持多元化,满足各种计算需求。
  4. 通过拆分函数,组合功能块,实现清晰、模块化的脚本结构。

掌握函数后,即可轻松应对 TouchDesigner 中的 CHOP/DAT/COMP execute 回调,将逻辑封装为可复用单元,构建高效自动化流程。
^1

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容