在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部分:
第一步.搭建图片合成节点
- 新建一个空项目,添加3个 Movie File InTOP ,导入3张准备好的图片。
- 给每个 Movie File InTOP 接一个 LevelTOP ,用于调整透明度。
- 把3个 LevelTOP 接入 CompositeTOP ,设置混合模式为 Add(或其他任意)。
- CompositeTOP 接入 WindowCOMP ,方便直接观察输出画面。
第二步.设置OSC接收节点
- 添加 OSC InDAT ,检查Port为7000(与 Processing 中的一致即可)。
- 运行Processing,成功可以收到 /switches 1 1 1 这样的数据。
第三步.筛选OSC数据
- 添加 SelectDAT,参数设置如图,会得到一行最新数据。
第四步.通过代码控制节点
- 添加 DAT ExecuteDAT ,连接 SelectDAT。
- 右键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脚本控制节点参数变化。
个人思路分享,欢迎评论讨论。