Houdini中给火花渲染准确的运动模糊 - 给运动模糊做非线性差值的方法以及固定粒子点数的方法

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

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

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

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

 1 2 3

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

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

通过吧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                 [email protected] = 1;
10                 break;
11         }else{
12                 @P = startPos;
13                 [email protected] = 0;
14         }
15 }

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

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

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

传统方法

非线性差值方法

时间: 2024-09-29 10:00:00

Houdini中给火花渲染准确的运动模糊 - 给运动模糊做非线性差值的方法以及固定粒子点数的方法的相关文章

Houdini中全景摄像机shader立体左右眼成像方法

熟悉Houdini Shader部分的同学应该多多少少也了解camera自身也可以设定自己的shader.其中polar panoramic shader 能够非常方便的为艺术家渲染360全景视角的cg画面,但是这样渲染出来的画面只是单眼所看到的环境,如果引入立体双摄像机的渲染方法的话,默认的这个摄像机shader就会出现一个严重的问题,那就是所渲染出来的画面是分别以各自两台摄像机位置为原点所计算出来的.用文字说明可能有点绕口,看下图: 图片中我把摄像头在一个水平轴向上移动了一点,渲染出来的结果

MVC 4中的前端渲染 @Helper指令

如果我们需要在一个页面或多个页面显示如人民币格式(后台传回来的无¥)¥的格式化.或是对后台数据作如保留小数个数等处理,这些东西经常要用到,特别是一些NULL值的处理,有可能会出错.这时我们可以通过创建 一个.csHtml文件(当然你也可以以把方法写在要用的当前页面中),封装一个方法, 直接在各个用到的前端面面中调用就可以了. 先举一个 在本页面调用,且写在本页面的使用如下: @{ Layout="~/Views/Shared/_Layout.cshtml" ; } @using  My

WPF中根据DPI获取准确坐标点啊

public class DPIUtils { private static double _dpiX = 1.0; private static double _dpiY = 1.0; public static double DPIX { get { return DPIUtils._dpiX; } } public static double DPIY { get { return DPIUtils._dpiY; } } public static void Init(System.Win

Cocos2D-x权威指南:通过节点控制屏幕中的全体渲染对象

本节,已经能够利用我们眼下所学的知识做出一些有趣的东西.之前已经说过,CCNode类没有贴图,也就是说在屏幕上单独建立一个节点是没有不论什么效果的,可是能够通过这个"无形"的节点来控制屏幕上的节点.如今就開始吧!     1. 增加节点    新建一个项目,并在HelloWorldScene.cpp文件里的init函数中做如代码清单3-2的代码所看到的的改动.     代码清单3-2 增加节点 bool HelloWorld::init() { if ( !CCLayer::init(

jQuery ZeroClipboard中Flash定位不准确的解决方案

转自波斯马,原文地址<jQuery ZeroClipboard中Flash定位不准确的解决方案> jQuery ZeroClipboard支持在多种浏览器中复制内容到剪贴板,IE.Firefox.Chrome等等都不在话下.其本身作为jQuery的一个插件封装了Zero Clioborad,其实现原理就是在要点击的按钮或链接上覆盖一个透明的Flash,实际上用户点击的是Flash,复制到剪贴板也是通过此Flash实现的. 大家用的很Happy,但是我用的时候发现点击按钮没有反应,后来发现是Fl

编程学习之如何在Node.js中优化服务器端渲染?[图]

编程学习之如何在Node.js中优化服务器端渲染?[图]在 Airbnb,我们花了数年时间将所有前端代码迁移到 React 架构,Ruby on Rails 在 Web 应用中所占的比例每天都在减少.实际上,我们很快会转向另一个新的服务,即通过 Node.js 提供完整的服务器端渲染页面.这个服务将为 Airbnb 的所有产品渲染大部分 HTML.这个渲染引擎不同于其他后端服务,因为它不是用 Ruby 或 Java 开发的,但它也不同于常见的 I/O 密集型 Node.js 服务.一说起 Nod

浅析Vue.js 中的条件渲染指令

1 应用于单个元素 Vue.js 中的条件渲染指令可以根据表达式的值,来决定在 DOM 中是渲染还是销毁元素或组件. html: <div id="app"> <p v-if="type===1">拌面</p> <p v-else-if="type===2">扁肉</p> <p v-else="type===3">其它</p> </div

3-7 Vue中的列表渲染

 举个案例:循环data中的list的值在div中,并显示相应的index值. 关于数组的循环: //显示效果如下图: //一般的列表渲染最好带一个key值,要把key值设置为唯一值的话,可以选择index.但在频繁操作DOM元素相对应的数据的时候,它还是有点浪费性能,可能让Vue没法充分复用DOM节点,所以不太建议用index来做key值 //所以一般的项目中的后端会传递过来一些数据,这些数据可以把它作为key值来使用(一般会携带一个后端或数据库相关的一个唯一的数据条目标识符,例如:id) /

vue03----生命周期、nextTick()、ref、filter、computed、vue中异步请求渲染问题(swiper不轮播)(在开发过程中遇到什么问题、踩过的坑)

### 1.vue的组件和实例都有生命周期,而且是一样的 生命周期:(组件从创建到销毁的过程) 创建 挂载 更新 销毁 组件到达某一个阶段就会自动触发某一些函数,这个函数就叫生命周期的钩子函数. 创建:组件创建的时候触发 beforeCreate created     组件刚创建的数据请求 挂载:创建完成挂载前后触发 beforeMount mounted     DOM的初始化操作 更新:数据发生改变的时候触发 beforeUpdate updated     数据的变化监听,尽量不要在这里