> 技术文档 > 在Processing通过OSC协议控制TouchDesigner节点_osc控制

在Processing通过OSC协议控制TouchDesigner节点_osc控制


视频:

https://www.bilibili.com/video/BV1ujgAzvEVq/?spm_id_from=333.1387.homepage.video_card.click&vd_source=a1ce17651f49542384f89fdd406973a9

前言:

本文介绍如何在Processing中通过OSC协议,实时控制TouchDesigner中的节点状态。主要用于展示基本流程,为扩展应用提供参考。

教程案例:使用Processing的3个按钮,通过OSC协议来控制TD中3张图片的透明度,实现图像的不同叠加效果。


软件:Processing(4.4.4),TouchDesigner(2023.11290)

环境:Win10

一.Processing部分:

以下为Processing端的代码,按顺序将代码粘贴到Processing中即可运行。代码包含彩蛋,不需要可自行删去。
运行前请确保已安装oscP5库。

第一步.导入库与声明全局变量

// === 导入 OSC 通信所需库 ===import oscP5.*;import netP5.*;// === 全局变量定义 ===OscP5 oscP5;NetAddress tdAddress;float[] switches = new float[3]; // 三个按钮状态(0/1)// 按钮参数int switchWidth = 30;int switchHeight = 70;float switchSpacing = 100;// 彩蛋文字显示时间int showMessageTime = 0;int displayDuration = 500;// 状态文字显示时间int stateMessageTime = 0;String monkeyMessage = \"\";

第二步.窗口设置与初始化

void settings() { size(400, 300); // 窗口大小}void setup() { surface.setTitle(\"Controller\"); surface.setLocation(50, 100); oscP5 = new OscP5(this, 12345); tdAddress = new NetAddress(\"127.0.0.1\", 7000); // 目标TD地址 for (int i = 0; i < 3; i++) switches[i] = 1; // 初始化为全部开启}

第三步.主循环逻辑

void draw() { background(240); drawInterface(); // 绘制 UI 与提示 sendOSC(); // 每帧发送状态}

第四步.绘制界面与状态提示

// === 界面绘制:顶部文字、按钮、提示 ===void drawInterface() { // 顶部文字动态动画 float t = frameCount * 0.05; float offsetX = sin(t) * 5; float offsetY = cos(t * 0.8) * 3; float angle = sin(t * 0.6) * 0.1; // 鼠标悬停放大文字 boolean isHoveringText = abs(mouseX - width / 2) < 80 && abs(mouseY - 40) < 20; float scaleFactor = isHoveringText ? 1.35 : 1.0; // 绘制顶部提示文字 pushMatrix(); translate(width / 2 + offsetX, 40 + offsetY); rotate(angle); scale(scaleFactor); fill(100); textAlign(CENTER, CENTER); textSize(15); text(\"Click to Toggle\", 0, 0); popMatrix(); // 绘制按钮 for (int i = 0; i < 3; i++) { float x = 100 + i * switchSpacing; float y = height / 2; drawSwitch(x, y, i); } // 判断是否全开/全关状态 if (switches[0] == 1 && switches[1] == 1 && switches[2] == 1) { if (!monkeyMessage.equals(\"BANANA\")) { monkeyMessage = \"BANANA\"; stateMessageTime = millis(); } } else if (switches[0] == 0 && switches[1] == 0 && switches[2] == 0) { if (!monkeyMessage.equals(\"There is NO MONKEY\")) { monkeyMessage = \"There is NO MONKEY\"; stateMessageTime = millis(); } } else { monkeyMessage = \"\"; } // 显示彩蛋,状态提示 String displayText = \"\"; if (millis() - showMessageTime < displayDuration) { displayText = \"Nice Try\"; } else if (millis() - stateMessageTime  0) { displayText = monkeyMessage; } // 绘制底部文字提示 if (displayText.length() > 0) { fill(120); textAlign(CENTER, CENTER); textSize(14); text(displayText, width / 2, height - 30); }}

第五步.绘制按钮

// === 单个按钮绘制 ===void drawSwitch(float x, float y, int index) { float radius = 15; float edgeWeight = 1; boolean isHover = isMouseOverSwitch(x, y); // 状态颜色 color baseColor = switches[index] == 1 ? color(80, 220, 100) : color(230, 80, 80); color hoverColor = switches[index] == 1 ? color(130, 255, 150) : color(255, 120, 120); color fillColor = isHover ? hoverColor : baseColor; // 按钮主体 strokeWeight(edgeWeight); stroke(150); fill(fillColor); rectMode(CENTER); rect(x, y, switchWidth, switchHeight, radius); // 点 noStroke(); fill(255, 255, 255, 50); float dotOffset = switchHeight / 4; ellipse(x, y + (switches[index] == 1 ? -dotOffset : dotOffset), 10, 10); // 编号和状态文字 textAlign(CENTER, CENTER); textSize(12); fill(150); text(\"No.\" + (index + 1), x, y - switchHeight / 2 - 12); textSize(16); text(switches[index] == 1 ? \"ON\" : \"OFF\", x, y + switchHeight / 2 + 14);}

第六步.处理鼠标点击与检测位置

// === 鼠标点击事件处理 ===void mousePressed() { // 点击顶部文字触发彩蛋 if (abs(mouseX - width / 2) < 80 && abs(mouseY - 40) < 20) { showMessageTime = millis(); } // 检测每个按钮是否被点击 for (int i = 0; i  x - switchWidth / 2 && mouseX  y - switchHeight / 2 && mouseY < y + switchHeight / 2;}

第七步.发送OSC数据

// === 发送 OSC 数据到 TouchDesigner ===void sendOSC() { OscMessage m = new OscMessage(\"/switches\"); for (float s : switches) m.add(s); oscP5.send(m, tdAddress);}

二.TouchDesigner部分:

第一步.搭建图片合成节点

  1. 新建一个空项目,添加3个 Movie File InTOP ,导入3张准备好的图片。
  2. 给每个 Movie File InTOP 接一个 LevelTOP ,用于调整透明度。
  3. 把3个 LevelTOP 接入 CompositeTOP ,设置混合模式为 Add(或其他任意)。
  4. CompositeTOP 接入 WindowCOMP ,方便直接观察输出画面。

第二步.设置OSC接收节点

  1. 添加 OSC InDAT ,检查Port为7000(与 Processing 中的一致即可)。
  2. 运行Processing,成功可以收到 /switches 1 1 1  这样的数据。

第三步.筛选OSC数据

  1. 添加 SelectDAT,参数设置如图,会得到一行最新数据。

第四步.通过代码控制节点

  1. 添加 DAT ExecuteDAT ,连接 SelectDAT
  2. 右键Edit Contents,写入以下代码。
    def onTableChange(dat): # 取第一行第一列字符串 line = dat[0,0].val.strip() # 判断是否以 /switches 开头 if not line.startswith(\"/switches\"): return # 拆分字符串,得到 [\"switches\", \"0\", \"0\", \"0\"] parts = line.split() if len(parts) < 4: return # 取后3个数字转int values = [int(x) for x in parts[1:4]] # 逐个设置对应Level TOP的不透明度(这里以 level1 ~ level3 为例) for i in range(3): level_op = op(f\'level{i+1}\') if level_op: level_op.par.opacity = values[i]

    (上面的脚本相当于 ConvertDAT - DAT toCHOP - SelectChop - MathChop 和映射的整合,不使用代码的版本如下图所示)

三.运行

完成以上操作即可运行,效果如下。

总结:

本文围绕Processing与TouchDesigner的联动控制,介绍了如何基于OSC协议,通过按钮交互实现远程节点参数的实时调控。Processing端构建了简易图形界面,通过OSC发送数据;TouchDesigner端接收并解析数据,并利用Python脚本控制节点参数变化。


个人思路分享,欢迎评论讨论。