Houdini中给火花渲染准确的运动模糊

摘要:
第一种是直接使用上面提到的速度进行线性差分,并用当前帧在两点之间进行线性采样,以获得运动的感觉。然后,这些子步骤将优先用于查找帧之间的中间值。第一图像中直接使用的速度值将用于插值模糊。然后,上面提到的所有子步骤将被转换为每个帧之间的线性插值(如图2所示)。稍后,我们将讨论如何解决时间线上粒子数量不断变化的问题。我们可以直接将线性位移动画提取到斩波器中,以进行更高级的非线性插值。

估计大家都知道使用运动速度来进行运动模糊的渲染,但是往往这个方法得到的运动模糊都是线性变化的,虽然乍一看没什么问题,但是如果想要每一帧的模糊轨迹也是有曲线变化的而不是僵硬的直来直去的话,使用trail算个速度来做的运动模糊是永远做不到这一点的。

这里我想通过常用的火花(spark)的运动模糊来讲一讲我所了解的一些比较好的方法。

所谓渲染中的运动模糊无非就是差值算法。目前使用的比较多的主要有两种。第一种就是上面说到的直接使用速度来线性差值,这种方法会计算每一个点的速度方向,计算出前一帧或者后一帧的位置,并与当前帧在两点之间进行线性采样这样就得到了运动的感觉。另一种直接是算的帧与帧之间的位移,让后把几何体变形差值来算出中间的模糊状态。其实两种方法大同小异,但是后者有一个好处是如果渲染目标是有subStep的话,那么会优先使用这些substep找到帧之间的中间值,那么substep就是我们得到准确运动效果的模糊。

在详说之前先看三张图的对比:

Houdini中给火花渲染准确的运动模糊第1张 1Houdini中给火花渲染准确的运动模糊第2张 2Houdini中给火花渲染准确的运动模糊第3张 3

三张图都是用的同一个点的旋转动画,在这里为了作比较我把相机shutter开为1,也就是每帧之间是全长度差值的,另外模糊偏移是设置为的0,也就是前帧取一半后帧取一半来完成当前帧的模糊渲染。第一张图直接使用的速度值来进行插值模糊,能够很明显的看得出最后形成的图案连一个闭环都算不上。第二张图使用的是传统的位移变换插值,但是在每一帧之间的substep都是线性变换的,所以能够看出来一个圆环高速转起来结果变成了一个类似多变形的效果。最后一个是用的我的方法计算出来的中间值,虽然不是绝对完美的匹配了圆环,但是曲线的效果非常明显,而且已经非常符合眼睛看到的残影。

如果我们在houdini里面使用的是脚本或者表达式来驱动的动画,我们大可不必为中间的substep担心,因为houdini会自己帮我们找到准确的位置,因为所有路径都是计算出来的,不论精确到哪一个时间点上。而如果我们把这些动画以几何体的形式转存到硬盘上,那么上面说的substep就会全部转成每一帧之间线性的插值(像图2)。而且这一点还是在拓扑和点数前后保持一致的前提下。在后面会讲怎么解决像粒子在时间线上点数不断变化的问题。我们可以把线性的位移动画直接提取到chop里面来进行更高级的非线性插值,从而达到运动模糊能够有圆滑的曲线感。如下图:

Houdini中给火花渲染准确的运动模糊第4张

通过吧P点数据以动画形式导入进去得到t[xyz]三条曲线,以当前帧为基础,分别多导入前后两帧(其实前后一桢也可以,不过两帧更安全),在使用resample节点在段与段之间加入新点。这里值得注意的是要使用cubic,也就是这个带来了非线性的感觉。而且这个方法也确保了之前的所有控制点都在曲线上,所以不会改变每个整数帧上点的位置。

插值的方法就是这个,再来讲一讲另一个用在火花上非常实际的问题,那就是点数不稳定的问题。上面所讲的方法一定是要建立在前后帧点数一定的前提下。所以如果粒子的生命不够动画长度的话,很可能就会使上面的方法直接死掉。不过这个问题也有一个突破口,那就是粒子有个点属性叫id。当动画调整完之后,我们拉到最后一帧可以很明确的知道最后一个id数是多少,这个数也代表了粒子一共出现过多少个。

解决这个问题的方法就是首先直接生成id最大数量的默认点,位置随便在哪都好(最好把初始位置放在发射源的中心点)。然后通过比对id数是否和自己的点数一致,一致的话吧粒子的位置和其他必要属性直接传个生成的这个固定点,这样就从变的点交接到了固定数目的点上去了。这个过程我使用的一点点vex:

 1 int popNum = npoints(1);
 2 vector startPos = point(2, "P", 0);
 3 
 4 for(int i = 0; i < popNum; i++){
 5         int popId = point(1, "id", i);
 6         if(@ptnum == popId){
 7                 vector popPos = point(1, "P", i);
 8                 @P = popPos;
 9                 f@alpha = 1;
10                 break;
11         }else{
12                 @P = startPos;
13                 f@alpha = 0;
14         }
15 }

这里的alpha是想让那些还没有动的点暂时渲染时不可见。

我之前说最好把初始位置放在发射源的中心点,是因为其实这个方法结合上面的模糊差值还是有一个小小的问题,那就是从默认点位置变换到粒子发射的点上,中间这段距离也会产生模糊,但是这个模糊是绝对不正确也不需要的,但好在粒子一般都是从物体表面或者体积内部发射出来的,我们完全可以用发射源来遮住这一帧的错误。

下面看看火花的效果对比,为了看效果快门还是用的1,但是明显能看出孰优孰劣了:

Houdini中给火花渲染准确的运动模糊第5张

传统方法

Houdini中给火花渲染准确的运动模糊第6张

非线性差值方法

免责声明:文章转载自《Houdini中给火花渲染准确的运动模糊》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇server的散热和Linux中温度的检測Java 之 clone 方法(对象拷贝)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android混淆

一、为什么要混淆 为了避免apk在发布后被用户通过反编译拿到源代码和资源文件,然后修改资源和代码之后就变成一个新的apk。而经过混淆后的APK,即使被反编译,也难以阅读,注意混淆不是让apk不能阅读,而是加大阅读的难度,为了避免劳动成果被窃取,也避免出现安全漏洞和隐患,所以在apk发布之前一定要进行混淆。 二、混淆的原理 Java是一种跨平台、解释型语言...

纹理映射 【转】

9.4 纹理对象 使用纹理对象来存储纹理数据的步骤: 1) 生成纹理对象名称 2) 将纹理对象绑定到纹理数据(包括图像数据数组和纹理属性), 即创建纹理对象. 3) 如果OpenGL实现高性能纹理工作集, 应检查是否有足够的空间来存储所有的纹理对象. 如没有足够空间, 应设置每个纹理对象的优先级, 以确保最常用的纹理留在工作集中 4) 绑定和重新绑定纹理对...

转:Oracle11g面向开发人员的重要新特性:Pivot 和 Unpivot

  Pivot 和 Unpivot使用简单的 SQL 以电子表格类型的交叉表报表显示任何关系表中的信息,并将交叉表中的所有数据存储到关系表中。Pivot如您所知,关系表是表格化的,即,它们以列-值对的形式出现。假设一个表名为 CUSTOMERS。 SQL> desc customersName                           ...

python的接口和抽象类

抽象基类有些面向对象的语言,如JAVA,支持接口,可以声明一个支持给定的一些方法方法,或者支持给定存取协议的类。抽象基类(或者ABCs)是Python里一个相同的特性。抽象基类由abc模块构成,包含了一个叫做ABCMeta的metaclass。这个metaclass由内置的isinstance()和issubclass()特别处理,并包含一批会被Pytho...

VMware报错:"激活连接失败:No suitable device found for this connection."

VMware安装之后正常使用,第二次使用时突然发现没有显示ip,操作系统也没显示有线连接,重启网络服务无效,报错如上图。 百度无数个方法,包括设置MAC地址,关闭networkManager等均无效。 后来发现主机上网络中心的VMware网络适配器显示无法识别的网络: 关于网络适配器无法识别网络的解决办法: 1,进入注册表[HKEY_LOCAL_MACH...

Effective C# 原则9:明白几个相等运算之间的关系(译)

Effective C# 原则9:明白几个相等运算之间的关系(译)Item 9: Understand the Relationships Among ReferenceEquals(), static Equals(), instance Equals(), and operator== 明白ReferenceEquals(), static Equal...