[{"data":1,"prerenderedAt":461},["ShallowReactive",2],{"page-RenderTarget-1":3,"page-count-RenderTarget":219},[4,257],{"id":5,"title":6,"body":7,"date":232,"description":13,"extension":233,"meta":234,"navigation":237,"path":249,"seo":250,"stem":251,"tags":252,"__hash__":256},"blogs\u002F_legacy\u002F2017\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note.md","UE4官方Multipass Rendering笔记",{"type":8,"value":9,"toc":217},"minimark",[10,14,25,28,31,35,38,45,48,51,57,60,66,69,72,78,81,84,90,93,99,102,105,108,113,116,122,125,129,132,138,141,146,149,152,155,160,163,166,169,172,175,181,185,188,191,194,198,201,204,208,211,214],[11,12,13],"p",{},"这是一篇记录性笔记，可能并没有什么实质性的内容。",[11,15,16,17,24],{},"看这个视频本质上就是出于一个误会，视频标题是",[18,19,23],"a",{"href":20,"rel":21},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=QGIKrD7uHu8",[22],"nofollow","Content-Driven Mulipass Rendering","，并不是针对某个特效的Step-by-step的教程，而是一些原理上的解释。",[11,26,27],{},"故而其中有很多内容都是关于3D渲染的公式和实现的，因此也就不会进行深入的研究。之所以选择UE4这样的引擎来做游戏，就是为了避免过度的接触细节。就像是学习高级语言之后，编译原理什么的粗略了解就可以了。",[11,29,30],{},"当然，遇到了非实现不可的特效的时候也没有办法。说实话，不太想和那些Paper呀、公式呀什么的打交道：D",[32,33,34],"h2",{"id":34},"材质原理",[11,36,37],{},"视频中提到的两个概念很有作用，就是Scatter和Gather",[11,39,40],{},[41,42],"img",{"alt":43,"src":44},"clip_image001","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image001_thumb.png",[11,46,47],{},"官方的RT示例中，水波纹扩散就是使用的Gather的方式进行运算的。",[11,49,50],{},"这是以前在理解上的一个误区，不能将整个运算目标当作一张贴图来看待，而应该去思考没一个区域（像素）应该处于什么状态。",[11,52,53],{},[41,54],{"alt":55,"src":56},"clip_image002","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image002_thumb.png",[11,58,59],{},"以及",[11,61,62],{},[41,63],{"alt":64,"src":65},"clip_image003","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image003_thumb.png",[32,67,68],{"id":68},"透视光学",[11,70,71],{},"视频中有提到水面的折射近似算法，就是所谓的Experience Based Magic Method。",[11,73,74],{},[41,75],{"alt":76,"src":77},"clip_image004","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image004_thumb.png",[11,79,80],{},"在光学现象中，还有提到chromatic aberration，也就是色差的实现方式。",[11,82,83],{},"色差的基础实现使用RGB Offset，不过演示中使用了spectral photons来进行。但pectral photons究竟是什么却没有搞明白，粗略搜索了一下也不得其门而入。感觉上像是光谱聚合吧，使用光谱这样的线条来进行模拟而不是根据点来进行计算，可以减少运算量。",[11,85,86],{},[41,87],{"alt":88,"src":89},"clip_image005","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image005_thumb.png",[11,91,92],{},"另外，色差是什么呢？可以参照维基百科的解释：",[94,95,96],"blockquote",{},[11,97,98],{},"色差是指光学上透镜无法将各种波长的色光都聚焦在同一点上的现象。它的产生是因为透镜对不同波长的色光有不同的折射率（色散现象）。",[11,100,101],{},"对于水面的模拟很有作用，不过实际上，这部分的原理并不是特别的重要，社区有个Ocean的项目对水面、水下的效果模拟都处理的比较好。",[32,103,104],{"id":104},"特效",[11,106,107],{},"在视频页面能够找到项目的下载地址，项目中就是在视频里面演示的那些效果。",[109,110,112],"h3",{"id":111},"flowmappainter","FlowMapPainter",[11,114,115],{},"基于RenderTarget绘制的FlowMap水面演示",[11,117,118],{},[41,119],{"alt":120,"src":121},"clip_image006","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image006_thumb.png",[11,123,124],{},"总体和ContentExample里面的RenderTarget在原理上是差不多的，使用的FlowMap也是材质节点，如果有用到的话可以参考一下。",[109,126,128],{"id":127},"fluidsimulation","FluidSimulation",[11,130,131],{},"流体模拟",[11,133,134],{},[41,135],{"alt":136,"src":137},"clip_image007","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image007_thumb.png",[11,139,140],{},"基于纳维－斯托克斯方程（Navier-Stokes equations）的流体模拟，这个方程可以参考下维基的解释：",[94,142,143],{},[11,144,145],{},"纳维－斯托克斯方程（Navier-Stokes equations），以克劳德-路易·纳维（Claude-Louis Navier）和乔治·斯托克斯命名，是一组描述像液体和空气这样的流体物质的方程。这些方程建立了流体的粒子动量的改变率（力）和作用在液体内部的压力的变化和耗散粘滞力（类似于摩擦力）以及重力之间的关系。这些粘滞力产生于分子的相互作用，能告诉我们液体有多粘。这样，纳维-斯托克斯方程描述作用于液体任意给定区域的力的动态平衡。",[11,147,148],{},"很复杂……",[11,150,151],{},"第一步，Advect，似乎是叫平流计算？不过日式的叫法移流方程式似乎更加的能方便理解，据说原理和上面的FlowMap的差不多。",[11,153,154],{},"第二步，计算散度，散度这个东西似乎以前物理中有学过。",[94,156,157],{},[11,158,159],{},"散度是向量分析中的一个向量算子，将向量空间上的一个向量场（矢量场）对应到一个标量场上。散度描述的是向量场里一个点是汇聚点还是发源点，形象地说，就是这包含这一点的一个微小体元中的向量是“向外”居多还是“向内”居多。举例来说，考虑空间中的静电场，其空间里的电场强度是一个矢量场。正电荷附近，电场线“向外”发射，所以正电荷处的散度为正值，电荷越大，散度越大。负电荷附近，电场线“向内”，所以负电荷处的散度为负值，电荷越大，散度越小。",[11,161,162],{},"就是这样的一个感觉。",[11,164,165],{},"第三步，计算压力；第四步，计算压力梯度。",[11,167,168],{},"这两步都是压力处理，在视频中讲解时似乎被算做了一步：D",[11,170,171],{},"每一步都会使用到部分前面计算的结果，全部都是通过RenderTarget进行中继的。",[11,173,174],{},"项目中有几个示例，分别是2D空间和3D空间内的流体模拟。",[11,176,177],{},[41,178],{"alt":179,"src":180},"clip_image008","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image008_thumb.png",[109,182,184],{"id":183},"hitmaskrender","HitMaskRender",[11,186,187],{},"就是在被命中的地方展示受到伤害的贴图，由于有密集恐惧症，就不贴图了，原理上比上面的都简单，就只是利用RenderTarget来做一个Mask而已。",[11,189,190],{},"但是其材质蓝图也是很复杂的，官方这个展示在各个细节方面都很\"认真\"。不仅仅做了mask，还有做法线上的Mask处理。",[11,192,193],{},"不过不知为何有几个地方有莫名的蓝图失连……所以怎么也没法把项目还原到官方视频中的那个效果。还有一个地方就是可能因为视频制作的时间比较靠前，在获取目标点的UV时，没有使用后面有的Trace UV功能，而是制作了一个UnWrap的Material来操作。",[109,195,197],{"id":196},"paintingvoluemtextures","PaintingVoluemTextures",[11,199,200],{},"非常酷炫的使用VR进行绘制的云的效果，是VR的……没法测试。",[11,202,203],{},"原理上和流体的应该差不多。",[109,205,207],{"id":206},"volumetextures","VolumeTextures",[11,209,210],{},"就是官方展示的那个3D的UV动画效果，使用了Custom Node，然后里面是有些复杂的Shader……",[32,212,213],{"id":213},"总结",[11,215,216],{},"果然做特效是件很复杂是事情，3D图形学实在可怕，还好引擎已经将大部分东西都封装好了，只要不追求酷炫，基本就不太需要关心这些，大概……",{"title":218,"searchDepth":219,"depth":220,"links":221},"",2,3,[222,223,224,231],{"id":34,"depth":219,"text":34},{"id":68,"depth":219,"text":68},{"id":104,"depth":219,"text":104,"children":225},[226,227,228,229,230],{"id":111,"depth":220,"text":112},{"id":127,"depth":220,"text":128},{"id":183,"depth":220,"text":184},{"id":196,"depth":220,"text":197},{"id":206,"depth":220,"text":207},{"id":213,"depth":219,"text":213},"2017-06-03","md",{"layout":235,"status":236,"published":237,"author":238,"author_login":240,"author_email":241,"wordpress_id":242,"wordpress_url":243,"date_gmt":244,"excerpt":245},"post","publish",true,{"display_name":239,"login":240,"email":241,"url":218},"风铃","flinkor","flinkor@foxmail.com",1765,"\u002F\u002F?p=1765","2017-06-03 08:26:07 +0000",{"type":8,"value":246},[247],[11,248,13],{},"\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note",{"title":6,"description":13},"_legacy\u002F2017\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note",[253,254,255],"UE4","RenderTarget","Rendering","NJsTELXWuLwdbFnOd8Ez1DGEBE4ywsugN5G3tLrwTSg",{"id":258,"title":259,"body":260,"date":446,"description":264,"extension":233,"meta":447,"navigation":237,"path":456,"seo":457,"stem":458,"tags":459,"__hash__":460},"blogs\u002F_legacy\u002F2017\u002F2017-04-23-ue4-render-target-preview.md","UE4渲染目标使用",{"type":8,"value":261,"toc":430},[262,265,268,271,280,283,286,292,296,299,303,306,311,314,317,320,323,326,329,332,335,338,341,346,349,352,355,360,363,366,370,373,376,380,383,387,390,393,396,401,404,407,410,415,418,421],[11,263,264],{},"UE4的Render Target提供了渲染缓存功能，可以制作很多有趣的特效。",[11,266,267],{},"当前UE4版本4.15.1。",[11,269,270],{},"Render Target作为一种动态生成内容的方法，为材质系统提供了更加精细的控制。引擎本身提供的Scene Capture功能也是可输出到Render Target并连接到材质上作为摄像展示功能的。通过Render Target也能实现类似神秘海域里面的擦拭物体表面灰层的功能。",[11,272,273,274,279],{},"本文参照[",[18,275,278],{"href":276,"rel":277},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FEngine\u002FRendering\u002FRenderTargets\u002FBlueprintRenderTargets\u002FOverview\u002Findex.html",[22],"官方文档","]进行完成，由于官方文档的介绍并不详细，所以在这里记录下自己的经验和理解。",[32,281,282],{"id":282},"高度场绘制器",[11,284,285],{},"高度场绘制器是通过将玩家操作反映到Render Target，然后传入材质来提升World Position来实现的，是一个非常简单的示例，基本按照官方的指引操作即可。",[11,287,288],{},[41,289],{"alt":290,"src":291},"image","\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-5.png",[109,293,295],{"id":294},"mat_heighfieldpainter","MAT_HeighfieldPainter",[11,297,298],{},"这个材质是最终应用到物体上的材质,Heightfield参数是Render Target的传入路径。可以看到，传入的高度场被拼接为(0,0,Z)的Vector输出到了World Position上，这就会导致被应用了材质的物体的对应位置向上偏移，同时传入的Render Target也到达了自发光颜色，使得升起的部分有了白色的效果。",[109,300,302],{"id":301},"mat_forcesplat","MAT_ForceSplat",[11,304,305],{},"这个材质是用来绘制Render Target的，直观的讲，就是在指定的点生成一个由内向外的Gradient一样的效果，作用到高度场上就是上图中那样的锥形效果。材质在实现上，首先根据传入的Force Position，mask之后，让其与UV相减，之后再求取向量长度的话，那么自然就会成为一个由那个点向外扩散的圆了：",[11,307,308],{},[41,309],{"alt":290,"src":310},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-6.png",[11,312,313],{},"这里要注意的是，UV在材质中是以左上角为(0,0)的，在材质蓝图中分别展示为R和G两个通道，但是负数全是黑色的。求出向量长度之后的操作就比较单纯了，通过减法和取整就可以得到目标的“圆点”了。",[109,315,316],{"id":316},"蓝图",[11,318,319],{},"蓝图的设置上比较方便，因为官方有提供在网页上复制蓝图脚步的功能，只要拷贝过去就可以了。基本上的功能也非常的直观。",[11,321,322],{},"在ConstructionScript中构建并指定材质，由于这里的功能比较简单，RenderTarget时在这里直接构建的；",[11,324,325],{},"在BeginPlay时打开Input交互，同时将RenderTarget设置给动态材质；",[11,327,328],{},"鼠标按下时标记MouseDown，此时Tick事件就会开始进行Trace操作；",[11,330,331],{},"整个蓝图的核心就是通过这个Trace给物体施加Damage事件，并在Damage处理中对进行RenderTarget的绘制。",[109,333,334],{"id":334},"绘制点的获取",[11,336,337],{},"需要注意的是，官方在获取绘制点的时候使用了一个简便的方法，这点官方也有给出注释说明。如果想要在所有的Mesh上都实现类似的效果，而不只是在例子中才能使用的话，需要使用Trace时获得的UV来进行计算。",[11,339,340],{},"而这个功能是4.13才有的新功能，要使用的话必须在项目设置>引擎>Physics中打开：",[11,342,343],{},[41,344],{"alt":290,"src":345},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-7.png",[11,347,348],{},"使用时要注意勾选Trace Complex才行。",[32,350,351],{"id":351},"流体表面",[11,353,354],{},"其实就是一个水波纹的效果，会在用户点击和玩家碰撞的地方产生扩散衰减的水波纹效果。是比高度图稍微复杂一些的效果，也是非常实用的效果。",[11,356,357],{},[41,358],{"alt":290,"src":359},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-10.png",[11,361,362],{},"由于需要的效果比较复杂，所以用到了三个缓存用Render Target以及一个绘制法线贴图的Render Target。",[11,364,365],{},"而相对的，绘制用材质ForceSplat可以采用高度场里面用到的材质，是一样的。",[109,367,369],{"id":368},"watermaterial","WaterMaterial",[11,371,372],{},"这个材质是应用于“水面”的材质，其本身的材质很简单，和通常的水面材质不同的是，将输入的Texture应用到了世界位置便宜与法线上。",[11,374,375],{},"其中Heightfield的应用方式与高度场的材质应用是相同的。",[109,377,379],{"id":378},"heightsim","HeightSim",[11,381,382],{},"这个是计算水面波纹的核心材质，原理上，首先将PreviousHeight1分别朝四个方向进行TexelSize单位的移动，然后相互叠加后与原有的图形进行相减，就能得到一个向外扩散的外沿了。之后再减去可以算作完全消退的PreviousHeight2作进一步的修正，就是当前的Height了。",[109,384,386],{"id":385},"computenormal","ComputeNormal",[11,388,389],{},"根据当前的绘制水面的高度图计算出法线贴图，使用的数学原理与HeightSim类似。",[109,391,316],{"id":392},"蓝图-1",[11,394,395],{},"蓝图实现上的整体逻辑和高度场示例中差不多，复杂之处在于使用tick函数来计算和更新了水波。其中最大的核心在这里：",[11,397,398],{},[41,399],{"alt":290,"src":400},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-8.png",[11,402,403],{},"每次计算的时候通过交换3个Render Target，分别作为Current，Prev1， Prev2来进行水波扩散的更新模拟计算，而法线的运算反而简单，只是在“绘制”执行的时候对“当前”水波进行法线计算而已。",[32,405,406],{"id":406},"小心有坑",[11,408,409],{},"官方亲切的提供了在网页中复杂蓝图节点的功能，但是要注意的是，当前版本中有一个BUG，材质蓝图中的所有参数名被多次使用时复制后会被自动重命名，并且这个过程是没有提示的，最后材质中就会变成这样：",[11,411,412],{},[41,413],{"alt":290,"src":414},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-9.png",[11,416,417],{},"此时材质参数无法正常传递，就会出现奇怪的特效。",[32,419,420],{"id":420},"源码",[11,422,423,424,429],{},"由于官方当前在文档中并没有提供一些必要的Mesh等资源，需要从Content Example中复制，为了方便大家研究，已经将完成的版本上传到了[",[18,425,428],{"href":426,"rel":427},"https:\u002F\u002Fgithub.com\u002Fsteinkrausls\u002FRtg_Test",[22],"GitHub","]上，欢迎取用。",{"title":218,"searchDepth":219,"depth":220,"links":431},[432,438,444,445],{"id":282,"depth":219,"text":282,"children":433},[434,435,436,437],{"id":294,"depth":220,"text":295},{"id":301,"depth":220,"text":302},{"id":316,"depth":220,"text":316},{"id":334,"depth":220,"text":334},{"id":351,"depth":219,"text":351,"children":439},[440,441,442,443],{"id":368,"depth":220,"text":369},{"id":378,"depth":220,"text":379},{"id":385,"depth":220,"text":386},{"id":392,"depth":220,"text":316},{"id":406,"depth":219,"text":406},{"id":420,"depth":219,"text":420},"2017-04-23",{"layout":235,"status":236,"published":237,"author":448,"author_login":240,"author_email":241,"wordpress_id":449,"wordpress_url":450,"date_gmt":451,"excerpt":452},{"display_name":239,"login":240,"email":241,"url":218},1615,"\u002F\u002F?p=1615","2017-04-23 14:26:42 +0000",{"type":8,"value":453},[454],[11,455,264],{},"\u002F2017-04-23-ue4-render-target-preview",{"title":259,"description":264},"_legacy\u002F2017\u002F2017-04-23-ue4-render-target-preview",[253,254],"bAxg5KEnuL8U7tmCW8-5niZcxunUKbD5aFWgOYaDb3o",1788763180071]