- 写在前面的废话 -
前段时间,当我打开之前讲过的使用Spring CHOP实现弹力线条的源文件,认真地看了下里面密密麻麻的节点、一行行的代码,当时我的内心:这谁做的啊,这么麻烦,这么多没用的节点和代码,我不写一行代码重做它好了。
翻了一下《代码本色》中Processing的实现原理和代码,原理和之前使用Spring CHOP的做法一样,但发现使用TD的一些TOP节点实现起来更加方便。下面就一起打开TD,不用一行代码实现弹力的效果吧。
就是这玩意
主要都是使用TOP节点计算
- 视频教程 -
第一次录制视频教程
- 制作思路 -
我们还是以之前TD杂谈02 - Spring CHOP中的弹力线条效果为例,这次主要是使用TD中的一些TOP节点去计算弹力,制作思路也是和之前讲解的思路一致,最终互动效果类似下方视频。
最终效果
主要步骤:一、制作25*3的点(列数自己确定)二、鼠标与线条的触发事件三、计算弹力(主要)四、音乐添加与触发
· 制作一排点并渲染成线条
像之前讲过的一样,我们需要制作一排线(这里是25 * 3),每根线有3个顶点,只使用中间顶点来计算弹力即可。
使用渐变方式为Horizontal和Vertical的两个Ramp TOP,接入Reorder,分别输出R和G通道,B通道设置为zero,我们将会得到25 * 3沿x、y的点。然后把点转成线条渲染出来。
这里需要注意的是,所有TOP的Pixel Format要设置成32bit,不然无法储存更多的数据。
转成线条、调整位置
· 鼠标与线条的触发事件
完成了基本的线条之后,我们先来实现鼠标与每根线的触发事件,在TD里面实现这个可以通过写代码或者使用Render Pick,使用TOP计算本质上也是和写代码一样,都是通过两点间的距离公式来判断鼠标当前位置触发了哪根线条。
两点间的距离公式
因为只需要用到x位置,把鼠标的x坐标转成TOP,使用Crop将中间的点提取出来并设置成32 bit float(Mono),接下来就是使用公式了。使用Subtract对两个数据相减,再使用Math进行平方和开方,移动鼠标接近每根线条,对应像素位置图像显示越黑(值越小),最后使用Threshold设置触发距离,并把触发信号转成0和1。
主要调的参数
做到这里,触发信号基本已经完成,因为现在信号是0和1的状态,我们需要使线条根据鼠标移动的快慢决定弹力的大小和鼠标移动的方向决定线条初始弹动的方向,这一步骤我们把弹力实现出来后再制作,这样就方便观看。接下来就到了最关键的步骤,计算弹力。
· 计算弹力
在开始制作前,先看一下Processing中的一个关于弹力的案例,我们根据里面核心的代码用TD的节点去实现。
https://processing.org/examples/springs.html
Processing中关于弹力的案例
force = -k * (tempypos - rest_posy); // f=-ky accel = force / mass; // Set the acceleration, f=ma == a=f/m vely = damp * (vely + accel); // Set the velocity tempypos = tempypos + vely; // Updated position
这个案例计算弹力用到的公式主要是上面这几行代码,tempypos是初始位置,对应到TD中的就是最开始时制作的线条中间点的x,rest_posy是鼠标的Y值,对应的是线条中间点的x加上鼠标移动产生差值的数据。k是弹力常数,mass是质量,damp是阻尼系数。接下来我们通过使用TOP节点一步步实现每一行代码。
f=-ky a=f/m
先把代码里的公式用节点连出来,把初始位置和上一步做完的触发信号(force)相减,然后再乘以弹力常数,除以质量,第一行和第二行代码在一个math里面计算了。
初始状态下,力和加速度是为零的,根据弹力运动的状态来看,我们能想到最终TOP里面的数据是初始位置加上一个来回闪动并在一定时间内归零的数据,而要让数据动起来,我们需要在初始位置后面添加一个Feedback。
vely = damp * (vely + accel)
这一步我们需要计算速度,初始状态下,速度也是为0,所以需要在这里使用constant创建一个为0的速度,在代码中,先抛开阻尼系数不管,vely = vely + accel,想要在数据动的时候每帧都加上原来的速度,我们需要再添加一个feedback,把最终相加的速度(add)给到feedback中。
到这一步,把数据和初始位置相加,移动鼠标,我们会发现TOP里面的颜色一直跳动不会停下来,这是因为阻尼系数还没有添加上去。
添加阻尼系数这一步需要注意,阻尼系数是在加速度相加之后再运算的,所以乘以阻尼系数需要在feedback后面进行运算,而不是在add节点后面。(最开始我就在这翻车了)
tempypos = tempypos + vely
最后把第一个feedback(这个feedback的target需要接入后面这个add)和速度相加(add),移动鼠标,线条的弹力就完成了。
数据需要闪动并逐渐消失
· 鼠标控制力的大小和方向
现在线条的弹力和方向都是一致的,我们把前面剩下的鼠标速度控制力的大小,左右控制方向添加上。
这一步其实和使用Feedback CHOP获取鼠标前后帧数据是一样的,但在TOP里面使用的不是Feedback,而是使用Cache存储前一帧的数据再相减。需要注意的是Cache中的always cook要打开。
因为前面的触发数据是0和1的数据,我们把鼠标前后帧的数据拉伸为同等的分辨率,和触发数据相乘就能实现根据鼠标移动速度作为力的大小。
到这里我们已经达到不写一行代码实现了之前使用Spring CHOP做的效果的目标了。
· 音乐添加和触发
前面的触发信号都做好了,音乐触发这里就很简单了。把音乐文件夹的Table拉到Audio Play参数中的Dat List中,使用触发信号调用Audio Play的play方法。等等,不是说不写一行代码吗... ...好吧,打脸了,要写一行,因为这方法是最方便了。
play(index, start=True, loop=False, delaySeconds=0.0, pan=None, rolloff=None, volume=None, fadeSeconds=0.0)

还是写了一行代码
说起音乐播放这事,想起自己当时真的是愚蠢。之前使用Spring CHOP做的那版,我是这样做的:有多少个音乐文件就用代码创建多少个 Audio File In,然后把输出都组合起来给到Audio Device Out。
用了超级多节点
整个案例制作就完成了,对比两种方法,使用TOP计算更加方便,不需要做太多的数据转化,也不需要写太多代码,在运行上效率也更快。
之前使用Spring CHOP做的那一版有很多节点可以简化掉的,毕竟是刚学TD不久的时候制作的,有时间再优化一下。
使用CHOP做的,里面还有很多节点
使用TOP做的,更加方便
- 结语 -
这次分享就到此结束了,公众号后台回复”SpringTOP“可获取TD文件下载地址。
以后我们会继续与大家分享一些关于使用TOP做一些公式、算法运算的技巧,敬请关注。
原创不易 你们的关注是我们的最大动力 Follow
关 注 我 们
#
学习交流分享,请多多指教
Touchdesigner · Notch · Arduino · Blender