[{"data":1,"prerenderedAt":1356},["ShallowReactive",2],{"blog-page-18":3,"blog-count":1355},[4,257,485,734,1235],{"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":469,"description":264,"extension":233,"meta":470,"navigation":237,"path":479,"seo":480,"stem":481,"tags":482,"__hash__":484},"blogs\u002F_legacy\u002F2017\u002F2017-05-21-ue4-new-animation-and-physics.md","UE4.16新动画与物理功能",{"type":8,"value":261,"toc":462},[262,265,274,278,281,284,287,293,296,301,304,309,312,315,320,323,329,332,335,339,342,347,350,355,358,362,365,368,373,376,381,384,388,391,394,399,402,407,410,415,418,423,426,431,434,439,442,447,450,453,456,459],[11,263,264],{},"4.16的Preview更新已经发布有一段时间了，与以往一样，这次的版本更新也带来了很多新的功能与改变。",[11,266,267,268,273],{},"本文主要参照官方的功能[",[18,269,272],{"href":270,"rel":271},"https:\u002F\u002Fwww.slideshare.net\u002FEpicGamesJapan\u002Funreal-engine-75203047",[22],"演示文稿","]进行整理完成。",[32,275,277],{"id":276},"基于rig的动画编辑","基于Rig的动画编辑",[11,279,280],{},"Rig是一种很方便的驱动骨骼动画的方式，本次的更新中添加了新的Rig动画编辑功能。",[11,282,283],{},"这个功能使得在编辑器中对Rig动画进行编辑变得可能，让我们进行更方便对动画调整和原型设计。",[11,285,286],{},"要想开启Rig动画编辑功能，首先要开启Control Rig插件：",[11,288,289],{},[41,290],{"alt":291,"src":292},"image","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-14.png",[11,294,295],{},"启用插件之后就可以在编辑器中看到这个模块到功能了：",[11,297,298],{},[41,299],{"alt":291,"src":300},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-15.png",[11,302,303],{},"中这个选项卡中新建一个Rig Sequence，然后拖一个骨骼Mesh进来当作目标，就可以在Sequence到编辑器中进行动画到编辑了：",[11,305,306],{},[41,307],{"alt":291,"src":308},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-16.png",[11,310,311],{},"编辑过程比较直观，也可以在IK与FK模式中进行切换，完成的动画可以导出成动画序列，在这个编辑器中也可以进行Retarget操作。",[11,313,314],{},"要导出动画，在Content Manager中找到Control Rig Sequence并点击右键，就可以看到相关到选项",[11,316,317],{},[41,318],{"alt":291,"src":319},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-17.png",[11,321,322],{},"然后就可以进行选择设置了",[11,324,325],{},[41,326],{"alt":327,"src":328},"SNAGHTML6685395","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002FSNAGHTML6685395_thumb.png",[11,330,331],{},"但是似乎没有看到从动画序列转换到Rig Sequence到方法。",[11,333,334],{},"Rig相关功能在4.16之后似乎还会增强，使得动画蓝图可以对Rig进行控制以及生成。",[32,336,338],{"id":337},"live-link","Live Link",[11,340,341],{},"很强大的功能，使得UE4与其他的3D编辑器可以实时的联动编辑。这样就能更加直观的看到需要做的内容做UE4中是如何工作的。",[11,343,344],{},[41,345],{"alt":291,"src":346},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-18.png",[11,348,349],{},"看起来非常的实用",[11,351,352],{},[41,353],{"alt":291,"src":354},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-19.png",[11,356,357],{},"不过这个似乎要到4.17才会进入试验阶段……",[32,359,361],{"id":360},"immediate-mode","Immediate Mode",[11,363,364],{},"之前的Physx是使用所谓保留模式（Retained Mode）工作的，Retained Mode有不少优点，方便实用。但是也有很多缺点，例如中对物体对Deactive逻辑处理时有不少效率上的问题、对物体进行遍历并不方便、很难对特定对物体组进行模拟成本计算等。",[11,366,367],{},"而Immediate Mode通过暴露出更多等底层操作接口，使得引擎能够更有效的对物理引擎进行控制和契合，同时也能大幅度的提升LOD以及Culing机制下的物理效率。",[11,369,370],{},[41,371],{"alt":291,"src":372},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-20.png",[11,374,375],{},"这个功能目前的一个主要应用是运动角色模型上的小的物体，这是一个在动画蓝图中的新节点：",[11,377,378],{},[41,379],{"alt":291,"src":380},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-21.png",[11,382,383],{},"它使得在动画蓝图中进行物理资源的模拟变得可能，这种方式比AnimDynamic的方式更方便进行操作，也具有更高的效率。",[32,385,387],{"id":386},"nvcloth","NvCloth",[11,389,390],{},"4.16开始UE4中开始使用NVIDIA的新的Cloth框架：NvCloth，它能直接在引擎中进行材质制作，大大的减少了以前必须使用Apex外部制作工具带来的很多麻烦。",[11,392,393],{},"同时NvCloth也获得了Immediate Mode的优势，使得Cloth的仿真效能得到增强。NvCloth也应用了新的空气阻力模型",[11,395,396],{},[41,397],{"alt":291,"src":398},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-22.png",[11,400,401],{},"要使用NvCloth首先需要中试验性功能中打开这个功能：",[11,403,404],{},[41,405],{"alt":291,"src":406},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-23.png",[11,408,409],{},"然后就可以在骨骼Mesh的编辑器中选中区域选择：",[11,411,412],{},[41,413],{"alt":291,"src":414},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-24.png",[11,416,417],{},"这之后选择相应的区域就可以对其进行Cloth绘制了：",[11,419,420],{},[41,421],{"alt":291,"src":422},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-25.png",[11,424,425],{},"添加后就能看到新的区域了",[11,427,428],{},[41,429],{"alt":291,"src":430},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-26.png",[11,432,433],{},"不过这里暂时没什么用，最主要的还是绘制的过程：",[11,435,436],{},[41,437],{"alt":291,"src":438},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-27.png",[11,440,441],{},"在窗口中能看到ClothPaint，打开之后进行权重绘制即可。",[11,443,444],{},[41,445],{"alt":291,"src":446},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-28.png",[11,448,449],{},"因为手头没有模型，无法进行绘制测试，看官方的演示的话，NvCloth无论是从效果上还是效率上都比原来的Apex路径强很多。",[32,451,452],{"id":452},"其他",[11,454,455],{},"在最近的引擎更新中有很多Robo Recall相关的功能实现被合并到了引擎中。",[11,457,458],{},"其中前向渲染的添加、运动物体上的CCD、pose snapshot、Constraint profile以及用于模拟移动有一定重量物体的Spring Lerp等已经在之前的版本中添加到了引擎中。",[11,460,461],{},"另外似乎有新的粒子系统在制作中，很期待接下来的版本更新。",{"title":218,"searchDepth":219,"depth":220,"links":463},[464,465,466,467,468],{"id":276,"depth":219,"text":277},{"id":337,"depth":219,"text":338},{"id":360,"depth":219,"text":361},{"id":386,"depth":219,"text":387},{"id":452,"depth":219,"text":452},"2017-05-21",{"layout":235,"status":236,"published":237,"author":471,"author_login":240,"author_email":241,"wordpress_id":472,"wordpress_url":473,"date_gmt":474,"excerpt":475},{"display_name":239,"login":240,"email":241,"url":218},1738,"\u002F\u002F?p=1738","2017-05-21 15:51:45 +0000",{"type":8,"value":476},[477],[11,478,264],{},"\u002F2017-05-21-ue4-new-animation-and-physics",{"title":259,"description":264},"_legacy\u002F2017\u002F2017-05-21-ue4-new-animation-and-physics",[253,386,483],"Animation","hEJJu0weqtXDxRLWNMRQ6X90OGRMe63j2oph88zyr_s",{"id":486,"title":487,"body":488,"date":717,"description":492,"extension":233,"meta":718,"navigation":237,"path":727,"seo":728,"stem":729,"tags":730,"__hash__":733},"blogs\u002F_legacy\u002F2017\u002F2017-05-03-ue4-physx-and-substepping.md","UE4中的Physx物理",{"type":8,"value":489,"toc":710},[490,493,496,499,503,506,509,514,517,522,525,528,531,536,539,543,546,549,554,557,560,565,568,572,575,585,588,594,597,605,611,614,620,623,629,632,640,643,646,652,655,661,664,668,671,674,677,680,686,695,698,701],[11,491,492],{},"为了保证物理引擎能够更精准的模拟，UE4有提供Physics Sub-Stepping功能，同时引擎也有提供相应的接口方便自行进行物理操作。",[11,494,495],{},"当前UE4版本4.16 P1。",[11,497,498],{},"UE4中对物理引擎的接口暴露还是相当多的，只是一般情况下不会使用到而已。",[32,500,502],{"id":501},"sub-stepping","Sub-Stepping",[11,504,505],{},"UE4的物理分步是所谓的半锁定步长形式的，无论如何分步的主要作用是提高物理模拟的精确度。针对的情况是，在不同的设备上，发布的程序可能会以不同的帧率运行。在有的设备上有可能会被进行奇怪的垂直同步设定，这些都有可能导致与帧率同步的物理模拟出现神奇的处理结果。",[11,507,508],{},"物理分步功能目前还不是特别完善，在代码中能看到注释：",[94,510,511],{},[11,512,513],{},"This feature is still experimental. Certain functionality might not work correctly",[11,515,516],{},"Sub-Stepping的设置在项目设置>Engine>Physics中。",[11,518,519],{},[41,520],{"alt":291,"src":521},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-2.png",[11,523,524],{},"在默认的情况下，不启用分布，作用于物理引擎的设定是Max Physics Delta Time。当前值是0.033333，也就是说物理引擎本身的运行不小于每秒30帧。",[11,526,527],{},"当启用了物理分步之后，引擎将会在每一帧中进行分步计算，当帧率下降到一帧时间大于最大分步数*最大分步时间的情况下，引擎将不再进行分步计算而是等待。无论如何，过小的物理分步将会导致更高的运算负荷，而且从某种程度上也并不是必要的。",[11,529,530],{},"引擎中有的与物理有关的代码中有提供bAllowSubstepping这样的选项来进行区分，当调用这些函数的来源是物理分步发出的事件时才需要将其置为FALSE。",[11,532,533],{},[41,534],{"alt":291,"src":535},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-3.png",[11,537,538],{},"物理分步还有三个扩展的属性，这些属性是分步时进行分步之间进行加权的平滑处理的。",[32,540,542],{"id":541},"async-scene","Async Scene",[11,544,545],{},"分步选项中还有一个Stepping Async的开关，这个选项是作用于Async Scene的，就是说是否对Async Scene进行分步计算。",[11,547,548],{},"但是Async Scene本身是需要另外开启的",[11,550,551],{},[41,552],{"alt":291,"src":553},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-4.png",[11,555,556],{},"在Physx中，有区分Synchronous与Asynchronous两种模式，而UE4中对其都有支持。Synchronous scene是通常的物理模拟发生的地方。而Asynchronous中存放的一般是可破坏物品等静态的、与游戏逻辑关联不大的物品。",[11,558,559],{},"静态的物品是同时存在于这两个Scene中的，而动态物品可以通过选项设定到Async Scene中。",[11,561,562],{},[41,563],{"alt":291,"src":564},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-5.png",[11,566,567],{},"但是静态物品会无视这个选项的，在碰撞中可以选择让物体在移动时也在Async Scene中检测碰撞。",[32,569,571],{"id":570},"custom-physics","Custom Physics",[11,573,574],{},"UE4中有提供介入物理引擎的方式，通过在bodyinstance或者PhysicsScene中定义的下面的函数进行事件绑定就好了：",[576,577,582],"pre",{"className":578,"code":580,"language":581},[579],"language-text","void AddCustomPhysics(FCalculateCustomPhysics& CalculateCustomPhysics);\n","text",[583,584,580],"code",{"__ignoreMap":218},[11,586,587],{},"与基本的Event Dispatcher的实现一样，要使用这个功能首先要声明一个",[576,589,592],{"className":590,"code":591,"language":581},[579],"FCalculateCustomPhysics OnCalculateCustomPhysics;\n",[583,593,591],{"__ignoreMap":218},[11,595,596],{},"而与通常的事件不同的是，AddCustomPhysics必须在每次Tick时都进行绑定，这样它才会在接下来的物理执行中被调用。",[11,598,599,600,604],{},"通常的Tick的",[18,601,603],{"href":602},"\u002F2017-03-25-ue4-time-mange\u002F#TickGroup","TickGroup","都是在PrePhiscs中的，也就是说这个注册是针对每一个引擎Tick循环进行的。",[576,606,609],{"className":607,"code":608,"language":581},[579],"void UMyStaticMeshComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)\n{\n  Super::TickComponent(DeltaTime, TickType, ThisTickFunction);\n  GetBodyInstance()->AddCustomPhysics(OnCalculateCustomPhysics);\n}\n",[583,610,608],{"__ignoreMap":218},[11,612,613],{},"而自己要定义的事件则绑定到OnCalculateCustomPhysics中就行了",[576,615,618],{"className":616,"code":617,"language":581},[579],"OnCalculateCustomPhysics.BindUObject(this, &UMyStaticMeshComponent::MyCustomPhysx);\n",[583,619,617],{"__ignoreMap":218},[11,621,622],{},"分发器本身的定义是",[576,624,627],{"className":625,"code":626,"language":581},[579],"DECLARE_DELEGATE_TwoParams(FCalculateCustomPhysics, float, FBodyInstance*);\n",[583,628,626],{"__ignoreMap":218},[11,630,631],{},"在使用自定义物理时，需要注意，一些物理相关的类型是无法进行蓝图暴露的。如果强行暴露给蓝图，例如添加UCLASS之类的修饰的话，就会不经提醒出现这样的报错:",[94,633,634,637],{},[11,635,636],{},"Unrecognized type 'FCalculateCustomPhysics' - type must be a UCLASS, USTRUCT or UENUM",[11,638,639],{},"Inappropriate '*' on variable of type 'FBodyInstance', cannot have an exposed pointer to this type.",[11,641,642],{},"其实只要把蓝图暴露的修饰符去掉就可以了。",[11,644,645],{},"另外如果要直接调用Physx的API的话，就必需在项目的build.cs中添加\"PhysX\"和\"APEX\" 这两个Module的包含，类似下面这样就可以了",[576,647,650],{"className":648,"code":649,"language":581},[579],"PublicDependencyModuleNames.AddRange(new string[] { \"Core\", \"CoreUObject\", \"Engine\", \"InputCore\", \"PhysX\", \"APEX\" });\n",[583,651,649],{"__ignoreMap":218},[11,653,654],{},"这样的话就可以通过",[576,656,659],{"className":657,"code":658,"language":581},[579],"PRigidBody = GetBodyInstance()->GetPxRigidBody_AssumesLocked();\n",[583,660,658],{"__ignoreMap":218},[11,662,663],{},"来进行Physx的API调用了。",[32,665,667],{"id":666},"damping-and-force","Damping and Force",[11,669,670],{},"Physx对球体的运动模拟上有些许问题，通常的建议是对球体作用Linear Damping和Angular Damping让其运动停止。",[11,672,673],{},"但是如果在对物理真实度要求较高的情况下就会有一个问题，那就是Damping在速度较高时减速比速度较低时快，而在速度接近零时需要一定的时间才能够停住运动。当然，如果Damping很高的情况下也是会直接停的。",[11,675,676],{},"所以我们可以通过对RigidBody直接施加力量来达到减速的效果。",[11,678,679],{},"但是通常情况下最好不要直接对速度进行修改，而是通过AddForce之类的操作间接的对速度进行操作。因为物理引擎内部很多模拟计算是以“当前”速度为基准进行的，如果直接进行速度的设置，可能会导致一些计算的结果不太真实。而AddForce的话就可以将加速度等计算交由物理引擎自行处理。",[576,681,684],{"className":682,"code":683,"language":581},[579],"void UNewStaticMeshComponent::SetBallVelocity(FVector fvVelocity, bool bAdd \u002F*= false*\u002F)\n{\n   if (bAdd && fvVelocity.Size() == 0.0f) return;\n\n  UE_LOG(LogTemp, Log, TEXT(\"[UNewStaticMeshComponent] SetBallVelocity: speed %s and %s add\"), *fvVelocity.ToString(), bAdd?TEXT(\"is\"):TEXT(\"not\"));\n  PxVec3 PNewVel = U2PVector(fvVelocity);\n  if (bAdd)\n  {\n    PRigidBody->addForce(PNewVel, physx::PxForceMode::eVELOCITY_CHANGE);\n  }\n  else\n  {\n     PRigidBody->setLinearVelocity(PNewVel);\n  }\n}\n",[583,685,683],{"__ignoreMap":218},[11,687,688,689,694],{},"这里需要注意的是，Physx与UE4的setLinearVelocity调用形式虽然是相同的，但第二个参数的意义是不同的。Physx的第二参数并不是Add to velocity而是auto wake。详细的addForce之类的可以参照[",[18,690,693],{"href":691,"rel":692},"http:\u002F\u002Fdocs.nvidia.com\u002Fgameworks\u002Fcontent\u002Fgameworkslibrary\u002Fphysx\u002Fapireference\u002Ffiles\u002FclassPxRigidBody.html",[22],"Physx文档","]。",[11,696,697],{},"这样的话再添加上一些接触判定逻辑就可以实现自己的球体运动模拟了。",[32,699,700],{"id":700},"源码",[11,702,703,704,709],{},"一些更多的细节部分请参考[",[18,705,708],{"href":706,"rel":707},"https:\u002F\u002Fgithub.com\u002Fsteinkrausls\u002FPhysxTest",[22],"Github","]上的源码，里面只保留了测试代码，有些多余的代码没有完全去掉~",{"title":218,"searchDepth":219,"depth":220,"links":711},[712,713,714,715,716],{"id":501,"depth":219,"text":502},{"id":541,"depth":219,"text":542},{"id":570,"depth":219,"text":571},{"id":666,"depth":219,"text":667},{"id":700,"depth":219,"text":700},"2017-05-03",{"layout":235,"status":236,"published":237,"author":719,"author_login":240,"author_email":241,"wordpress_id":720,"wordpress_url":721,"date_gmt":722,"excerpt":723},{"display_name":239,"login":240,"email":241,"url":218},1659,"\u002F\u002F?p=1659","2017-05-03 15:15:23 +0000",{"type":8,"value":724},[725],[11,726,492],{},"\u002F2017-05-03-ue4-physx-and-substepping",{"title":487,"description":492},"_legacy\u002F2017\u002F2017-05-03-ue4-physx-and-substepping",[253,731,732],"物理","Substeping","6Y9M-KkcwG2tKy8g5yLG0UdDxx2RabVFCSooiRT8HNI",{"id":735,"title":736,"body":737,"date":1216,"description":741,"extension":233,"meta":1217,"navigation":237,"path":1226,"seo":1227,"stem":1228,"tags":1229,"__hash__":1234},"blogs\u002F_legacy\u002F2017\u002F2017-05-01-ue4-patch-release-dlc.md","UE4补丁与DLC",{"type":8,"value":738,"toc":1201},[739,742,745,748,752,761,764,767,773,776,781,784,789,792,799,804,807,812,821,824,829,832,837,840,845,848,851,854,859,863,866,869,872,877,880,885,888,892,895,898,904,907,910,915,919,922,927,930,935,938,943,946,949,969,972,976,979,982,985,993,996,999,1002,1007,1010,1016,1019,1022,1025,1028,1032,1035,1038,1041,1044,1055,1058,1061,1064,1068,1071,1077,1080,1085,1088,1093,1096,1099,1102,1105,1110,1113,1117,1120,1126,1129,1132,1137,1140,1143,1146,1152,1155,1160,1163,1166,1171,1174,1177,1182,1185,1190,1193,1196,1198],[11,740,741],{},"UE4的打包操作本身还是比较简单的，但是考虑到发布之后的升级与补丁，却还是有一些麻烦。",[11,743,744],{},"当前UE4版本为4.16 P1。",[11,746,747],{},"在动手做东西之前，先了解一下UE4本身对于打包系统的架构是很重要的，否则如果到了Release的阶段发现代码设计上很多地方与系统有冲突的话就会很麻烦。就像是等到开始做联网版本的游戏时才发现很多机制、功能的设计都与UE4的Replication架构不符的话就会需要大幅度的代码变更。",[32,749,751],{"id":750},"unreal-frontend","Unreal Frontend",[11,753,754,755,760],{},"虚幻的打包操作在[",[18,756,759],{"href":757,"rel":758},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FEngine\u002FDeployment\u002Findex.html",[22],"官方文档","]中有进行描述，一切打包相关的工作，都以Unreal Frontend为核心进行。当然，Unreal Frontend还提供了部署、自动化测试等功能。",[11,762,763],{},"总体而言，Unreal Frontend的功能还不成熟，很多选项的设定让人费解，也没有提供足够的文档说明，所以可能会遇到一些奇怪的BUG。最麻烦的是，到目前为止，DLC系统依然处于WIP状态，使用起来有很多的不便。",[11,765,766],{},"目前主要会使用到的是Project Launcher模块，在下方的Custom Lanch Profiles区域的右边有加号按钮，可以在那里添加自定义的打包配置。配置大致分为以下区域：",[11,768,769],{},[770,771,772],"strong",{},"Project",[11,774,775],{},"选择打包操作的目标项目，由于Unreal Frontend的设置是全局的，所以在一个项目中配置了之后在其他项目中也可以使用。",[11,777,778],{},[770,779,780],{},"Build",[11,782,783],{},"选择是否构建，以及构建的模式，并提供了是否构建UAT（Unreal Automation Tool）的选项。UAT主要提供一些自动化测试方面的功能，根据社区一些用户的反馈来看，需要源码版本引擎才能正常的使用。",[11,785,786],{},[770,787,788],{},"Cook",[11,790,791],{},"烘焙相关选项，一般都是用By the book选项然后勾选相关目标平台。",[11,793,794,795,694],{},"进行Release\u002FPatch\u002FDLC打包的操作都在By the book选项下。其他的一些详细的可选项功能可以参考[",[18,796,759],{"href":797,"rel":798},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FEngine\u002FDeployment\u002FCooking\u002Findex.html",[22],[11,800,801],{},[770,802,803],{},"Package",[11,805,806],{},"是否打包以及如何打包，这里需要注意的是当前版本下对DLC进行打包是会出现BUG的，报错如下：",[94,808,809],{},[11,810,811],{},"Program.Main: ERROR: AutomationTool terminated with exception: System.Exception: Couldn't update resource",[11,813,814,815,820],{},"搜索之后发现似乎是一个[",[18,816,819],{"href":817,"rel":818},"https:\u002F\u002Fissues.unrealengine.com\u002Fissue\u002FUE-42880",[22],"BUG","]，因此目前对DLC可以不需要打包，而是自己将生成的文件进行拷贝就可以了。",[11,822,823],{},"打包的生成目录在Saved\\StagedBuilds\\中。",[11,825,826],{},[770,827,828],{},"Archive",[11,830,831],{},"归档，引擎会在打包后将打包好的内容拷贝到指定的目录去。不使用的话不要勾选就可以了。",[11,833,834],{},[770,835,836],{},"Deploy",[11,838,839],{},"部署，提供了几种部署渠道，可以部署到目前可用的设备上。不使用的话可以直接选中Not Deploy。",[11,841,842],{},[770,843,844],{},"Launch",[11,846,847],{},"测试运行的形式，可以对服务端模式、语言环境、初始地图等进行设置。",[32,849,850],{"id":850},"打包模式",[11,852,853],{},"打包模式目前有Release、Patch、DLC三种，其中DLC处于WIP状态，并没有足够的文档支持，而且今后可能会有不少变动。",[11,855,856],{},[41,857],{"alt":291,"src":858},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb.png",[109,860,862],{"id":861},"release-version","Release Version",[11,864,865],{},"UE4提供的Release的概念是通常的发行版本控制，勾选Create a release version of the game for distribution就可以开启了。而Patch与DLC都是以某个Release版本为基础进行打包的。",[11,867,868],{},"因此使用Release打包的时候就必须填Name of the new release to create，而Path与DLC则必须填写Release version this is based on。",[11,870,871],{},"DLC是不可以选中Create a release version这个选项的，会报错：",[94,873,874],{},[11,875,876],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Can't create a release version at the same time as creating dlc.",[11,878,879],{},"而选中了这个选项还填写based on version的话也会报错：",[94,881,882],{},[11,883,884],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Only staged builds can be paked, use -stage or -skipstage.",[11,886,887],{},"这个错误也会出现在使用Iterative cooking选项时，如果使用这个选项同时又勾选使用Pak的话，根据当前烘焙缓存的状况不同，也会报这个错。",[109,889,891],{"id":890},"generate-patch","Generate patch",[11,893,894],{},"生成补丁，目前一个Release下只能有一个补丁，对于生成的pak文件，补丁中带后缀_P，会被优先加载并覆盖。同样的pak文件，多加一个_P的话优先级就会更高。",[11,896,897],{},"在Mount函数中，可以看到",[576,899,902],{"className":900,"code":901,"language":581},[579],"if ( PakFilename.EndsWith(TEXT(\"_P.pak\")) )\n{\n  PakOrder += 100;\n}\n",[583,903,901],{"__ignoreMap":218},[11,905,906],{},"凡是以_P结尾的pak文件，会获得额外的100优先级。在进行Patch打包时，引擎也会自动的加上这个后缀。",[11,908,909],{},"这里有一个问题，如果勾选了Store all content in a single file的情况下，即便是在不同的Release版本之间，_P的patch也会被优先加载。还没有测试过如果去除了Save package without versions选项是否会有这样的现象。",[11,911,912],{},[41,913],{"alt":291,"src":914},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-1.png",[109,916,918],{"id":917},"iterative-cooking","Iterative cooking",[11,920,921],{},"增量烘焙必须去掉勾选Save package without versions，否则launch按钮会变成灰色，提示：",[94,923,924],{},[11,925,926],{},"unversioned build cannot be incremental",[11,928,929],{},"这里面的Iterative cooking目前只能在同一个Release版本中进行增量烘焙，如果Releasse的版本迁移了的话，是不能在版本之间进行增量烘焙的，强行勾选会被拒绝操作：",[94,931,932],{},[11,933,934],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Can't use iterative cooking \u002F deploy on dlc or patching or creating a release",[11,936,937],{},"官方的说明是这样的：",[94,939,940],{},[11,941,942],{},"The asset registry and pak file will be needed for any future patches or DLC to check against.",[11,944,945],{},"也就是说保存的content注册关系是为了DLC和patch而存在的，并没有说可以作为Release之间的版本迁移的依据。",[11,947,948],{},"使用Iterative cooking时还有一点需要注意，那就是引擎当前无法区分Ship和DevelopMent之间的烘焙结果，如果切换Build模式时没有去掉这个选项的话，就会导致烘焙资源的混杂，出现类似如下错误：",[94,950,951,966],{},[11,952,953,954,958,959,962,963],{},"Assertion failed: GDefaultMaterials",[955,956,957],"span",{},"Domain"," != NULL ",[955,960,961],{},"File:D:\\Build++UE4+Release-4.16+Compile\\Sync\\Engine\\Source\\Runtime\\Engine\\Private\\Materials\\Material.cpp"," ",[955,964,965],{},"Line: 429",[11,967,968],{},"Cannot load default material 'engine-ini:\u002FScript\u002FEngine.Engine.DefaultMaterialName'",[11,970,971],{},"另外，使用增量会导致不在当前选择的地图内容也会被Build进来，但是无论如何，项目设定中的默认地图都是会别build进来的。",[109,973,975],{"id":974},"build-dlc","Build DLC",[11,977,978],{},"UE4中的DLC是以Plugin的形式进行实现的，DLC Name那里填写的就是插件的名称，是不能随便乱填的。",[11,980,981],{},"插件的话在Plugins窗口直接新建就可以了，如果是蓝图项目的话，只会有一个Content Plugin，选择他就可以了。另外，似乎在打包时如果有地图存在的话，没有被地图引用的资源就不会被打包，需要注意。",[11,983,984],{},"打包DLC中如果出现",[94,986,987,990],{},[11,988,989],{},"Cook: LogInit:Display: LogCook:Error: Engine or Game content ..\u002F..\u002F..\u002FEngine\u002FContent\u002FTutorial\u002FFoliage\u002FFoliage_Intro_Tutorial.uasset is being referenced by DLC!",[11,991,992],{},"Cook: LogInit:Display: LogCook:Error: Engine or Game content ..\u002F..\u002F..\u002FEngine\u002FContent\u002FTutorial\u002FSubEditors\u002FDestructibleMeshEditorTutorial.uasset is being referenced by DLC!",[11,994,995],{},"之类的BUG，可以尝试勾选Include engine content。",[11,997,998],{},"关于DLC，一些旧的资料中会提到Plugin形式无法被引擎自动加载，目前测试过已经没有这个现象了。即便是在Release之后添加的Plugin，在做DLC的打包之后，直接扔到项目目录中也会被自动加载。不知是否是因为使用DevelopMent打包的关系。",[11,1000,1001],{},"由于当前Package DLC不知为何会报错，类似这样",[94,1003,1004],{},[11,1005,1006],{},"UATHelper: Packaging (Windows (64-bit)): Program.Main: ERROR: AutomationTool terminated with exception: System.Exception: Couldn't update resource",[11,1008,1009],{},"其实Pak已经打包成功了，直接Achive即可。",[11,1011,1012],{},[41,1013],{"alt":1014,"src":1015},"msohtmlclipclip_image0014","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0014_thumb.png",[11,1017,1018],{},"将生成的内容直接复制到打包程序里面，就会被自动加载了，即便Release打包的时候并没有这个DLC的Plugin也是可以的。",[32,1020,1021],{"id":1021},"补丁形式",[11,1023,1024],{},"官方在Patch的文档中有提到补丁的覆盖优先，由于Patch是从Release的版本开始进行差分的，如果两个Patch都是针对整个游戏的话，那么前一个Patch就没有意义了，可以删除。",[11,1026,1027],{},"这样一来，为了防止每次更新的内容过大，我们就必须对项目的组织进行设计，目前我们可以通过Maps或者Chunks来做内容差分管理。",[109,1029,1031],{"id":1030},"maps","Maps",[11,1033,1034],{},"在进行打包时，被打包地图及其所引用的资源有改变的都会被打包，只是是否会被游戏采用取决于Pak的加载优先级。",[11,1036,1037],{},"而不被选中的地图中，即便相关资源有变动，也不会被打包到Patch中去，但是DefaultMap始终都会被打包。",[11,1039,1040],{},"各个地图打包之后除了DefaultMap之外都是独立的，无论命名成什么都会被自动加载，而_P的优先级会被应用到整个Pak文件上。",[11,1042,1043],{},"而目前，只要在扫描目录里面的pak文件，都会被自动加载。从FPakPlatformFile::Initialize的调用中看到，除了在SHIPPING模式下提供的命令行外，有如下的目录会被添加到扫描中：",[94,1045,1046,1049,1052],{},[11,1047,1048],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::GameContentDir()));",[11,1050,1051],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::GameSavedDir()));",[11,1053,1054],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::EngineContentDir()));",[11,1056,1057],{},"也就是说，可以在一开始打包时，只选中Default地图，之后其他的地图可以每个或每组地图单独选中，然后打包成Patch改成地图名称的形式添加到游戏中去。",[11,1059,1060],{},"这样一来，就可以很方便的添加后续的地图内容到发布版本中去了，只是多少还需要维护一个文件列表。",[11,1062,1063],{},"总体而言，使用一个空地图作为程序本体，将通用的逻辑、材质放到其中，其他地图大致保持各自独立。这样每次就可以对对应的模块进行更新替换就行了。",[109,1065,1067],{"id":1066},"chunks","Chunks",[11,1069,1070],{},"Chunks这个功能可以在编辑器中指定内容将会被打包到哪一个Patch中去，但是这个功能必须在编辑器设定中Genera>Experiment中打开：",[11,1072,1073],{},[41,1074],{"alt":1075,"src":1076},"msohtmlclipclip_image001","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image001_thumb.png",[11,1078,1079],{},"打开选项之后，就可以在内容管理器的右键菜单中看到：",[11,1081,1082],{},[41,1083],{"alt":291,"src":1084},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-6.png",[11,1086,1087],{},"Chunk相关的选项了。对不同的资源设定了Chunk之后就可以在打包时选中这个功能，打包之后就会有不同的分包了。",[11,1089,1090],{},[41,1091],{"alt":291,"src":1092},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-7.png",[11,1094,1095],{},"Chunk功能必须在Pak开启时使用，因为不Pak打包的话，原本的项目文件就已经足够Chunk了。",[11,1097,1098],{},"另外，如果要使用Http chunk install功能的话，不要将Default Map放到Chunk中去，否则由于本地不会保留那些Chunk，程序将会由于没有Default Map而无法开启。",[11,1100,1101],{},"如果对在Patch的时候也使用chunk的话，将会对不同的chunk包生成Patch，但是即使该chunk包的内容没有改变，也依然会生成一个1K的Dammy。",[11,1103,1104],{},"不过这其中最大的限制是，对chunk进行patch时只能针对Release时在AssetRegistry注册过的地图，如果添加没有注册过的地图则无法打包成功。",[94,1106,1107],{},[11,1108,1109],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.CommandUtils+CommandFailedException: Command failed (Result:3): D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64\\UnrealPak.exe F:\\Ue_Patch\\1.0_nomap\\WindowsNoEditor\\P001\\Content\\Paks\\P001-WindowsNoEditor_P.pak -create=\"C:\\Users\\Admin\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakList_P001-WindowsNoEditor_P.txt\" -encryptionini -enginedir=\"D:\\Code\\UE_4.16\\Engine\" -projectdir=\"E:\\Ues\\P001\" -platform=Windows -abslog=\"C:\\Users\\Admin\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakLog_P001-WindowsNoEditor_P.log\" -installed -order=E:\\Ues\\P001\\Build\\WindowsNoEditor\\FileOpenOrder\\CookerOpenOrder.log -UTF8Output -generatepatch=E:\\Ues\\P001\\Releases\\5.0\\WindowsNoEditor\\P001-WindowsNoEditor.pak -tempfiles=D:\\Code\\UE_4.16\\TempFiles -multiprocess -patchpaddingalign=2048. See logfile for details: 'UnrealPak-2017.05.07-11.00.34.txt'",[11,1111,1112],{},"会出现类似这样的错误。",[109,1114,1116],{"id":1115},"http-chunks-install","Http Chunks Install",[11,1118,1119],{},"在使用Chunk的基础上，还可以进一步的使用Http Chunks Install功能，这个功能通常被用于移动端的碎片化安装功能",[11,1121,1122],{},[41,1123],{"alt":1124,"src":1125},"msohtmlclipclip_image0016","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0016_thumb.png",[11,1127,1128],{},"不过在桌面端也可以进行使用。其实实现中并没有支持断点续传，不过事实上，分块下载本身就在一定程度上充当了断点续传的功能。",[11,1130,1131],{},"使用起来也比较简单，直接勾选并填写输出路径、版本名称之类的就可以了。",[11,1133,1134],{},[41,1135],{"alt":291,"src":1136},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-13.png",[11,1138,1139],{},"不过要注意确保其输出目录是确实存在的，和其他的目录设定不同，这里是会进行写入检测的。",[11,1141,1142],{},"另外，在Chunk Version Name里面输入之后记得敲回车才能确认输入。这里的输入框功能有点奇怪，直接填完之后点别的地方不会确认输入，会直接清空。",[11,1144,1145],{},"如果是移动端打包的话，无需添加配置文件，直接点击添加按钮盘的下拉三角即可：",[11,1147,1148],{},[41,1149],{"alt":1150,"src":1151},"msohtmlclipclip_image0011","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0011_thumb.png",[11,1153,1154],{},"打包成功的话会在输出目录输出类似这样的内容：",[11,1156,1157],{},[41,1158],{"alt":291,"src":1159},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-8.png",[11,1161,1162],{},"Http chunk install的功能也是以一个chunk为目标进行的，只是每个chunk会被分成更小的块，方便传输。也就是说，要使用这个功能，还是需要有一个自行设计的文件列表来进行版本管理的。",[11,1164,1165],{},"要进行碎片安装，直接对某个文件执行Request Content：",[11,1167,1168],{},[41,1169],{"alt":291,"src":1170},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-9.png",[11,1172,1173],{},"这里面填写的URL对应的就是上面生成的那些内容，需要自行部署到服务器上。",[11,1175,1176],{},"如果Success的话，会返回一个Mobile Pending Content的引用，继续",[11,1178,1179],{},[41,1180],{"alt":291,"src":1181},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-10.png",[11,1183,1184],{},"如果成功的话就可以对这个引用进行Mount了",[11,1186,1187],{},[41,1188],{"alt":291,"src":1189},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-11.png",[11,1191,1192],{},"这样就可以使用这个包的内容了，这套函数本身会检测本地有没有pak文件，有的话就不会进行下载了。",[11,1194,1195],{},"上面填写的Install Directory在windows下是以项目内容目录下的PersistentDownloadDir为基础的，所以填写..\u002FContent\u002FPaks\u002F的话就可以到达自动加载目录，下次游戏运行时包中的内容就可以直接使用了。不过要留意的是，如果被自动加载了的话，那个文件就无法被直接替换掉了。",[32,1197,213],{"id":213},[11,1199,1200],{},"由于UE4并未提供Release版本之间的增量功能，要实现地图下载之类的功能的话，可以使用DLC或者分Map打包。如果现在的打包实在无法满足需求的话，也可以选择自己用UnreakPack进行打包并自行进行Mount管理来进行补正，有这个需求的话可能会遇到FPackageName::RegisterMountPoint之类函数的使用。不过相信打包功能在之后的版本更新中会有所增强，如果不是有紧急的打包需求的话，不建议跳这个坑。",{"title":218,"searchDepth":219,"depth":220,"links":1202},[1203,1204,1210,1215],{"id":750,"depth":219,"text":751},{"id":850,"depth":219,"text":850,"children":1205},[1206,1207,1208,1209],{"id":861,"depth":220,"text":862},{"id":890,"depth":220,"text":891},{"id":917,"depth":220,"text":918},{"id":974,"depth":220,"text":975},{"id":1021,"depth":219,"text":1021,"children":1211},[1212,1213,1214],{"id":1030,"depth":220,"text":1031},{"id":1066,"depth":220,"text":1067},{"id":1115,"depth":220,"text":1116},{"id":213,"depth":219,"text":213},"2017-05-01",{"layout":235,"status":236,"published":237,"author":1218,"author_login":240,"author_email":241,"wordpress_id":1219,"wordpress_url":1220,"date_gmt":1221,"excerpt":1222},{"display_name":239,"login":240,"email":241,"url":218},1646,"\u002F\u002F?p=1646","2017-05-01 10:32:13 +0000",{"type":8,"value":1223},[1224],[11,1225,741],{},"\u002F2017-05-01-ue4-patch-release-dlc",{"title":736,"description":741},"_legacy\u002F2017\u002F2017-05-01-ue4-patch-release-dlc",[253,1230,1231,1232,1233],"Release","Patch","DLC","UnrealPak","cJwigzRyewKqORjMzLTqhnQa8zSJWqk_pxLSbY0jaAA",{"id":1236,"title":1237,"body":1238,"date":1339,"description":1242,"extension":233,"meta":1340,"navigation":237,"path":1349,"seo":1350,"stem":1351,"tags":1352,"__hash__":1354},"blogs\u002F_legacy\u002F2017\u002F2017-04-26-ue4-active-class-redirects.md","UE4资源重定向",{"type":8,"value":1239,"toc":1335},[1240,1243,1246,1249,1252,1257,1260,1266,1269,1272,1275,1282,1288,1291,1294,1297,1303,1306,1309,1312,1317,1320,1326,1332],[11,1241,1242],{},"在混合使用C++和蓝图进行编码时，有时会因为代码的变动而导致蓝图无法正确的识别基础的类。此时可以使用资源重定向进行解决。",[11,1244,1245],{},"当前UE4版本4.15.1。",[11,1247,1248],{},"如果是在内容管理器中进行删除、重命名、移动等操作的话，引擎会尝试自动执行重定向，或者给出提示。只要不操作失误的话就不会有什么大问题。",[11,1250,1251],{},"但当C++定义的基类由于各种原因不存在时，由于引擎不会给出提示，有时就会出现灾难性的结果，比如这样：",[11,1253,1254],{},[41,1255],{"alt":291,"src":1256},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-11.png",[11,1258,1259],{},"或者更严重的，变成这样：",[11,1261,1262],{},[41,1263],{"alt":1264,"src":1265},"SNAGHTMLf68450","\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002FSNAGHTMLf68450_thumb.png",[11,1267,1268],{},"由于蓝图的基类不存在了，这时候就算强行打开蓝图类，也有可能会变成奇怪的情况。引擎本身无法识别基类，蓝图的类型判定就会出错，即便有替换的目标类也无法进行指定。想要将基类指定为AActor都无法进行。如果此时有作为替换的类的话，就可以求助于资源重定向了。",[32,1270,1271],{"id":1271},"重定向配置",[11,1273,1274],{},"资源重定向可以在配置文件DefaultEngine.ini中设定，这个文件位于项目目录下Config目录中。",[11,1276,1277,1278,1281],{},"在其中找到",[955,1279,1280],{},"\u002FScript\u002FEngine.Engine","，如果没有的话直接添加即可，按照如下格式添加即可：",[576,1283,1286],{"className":1284,"code":1285,"language":581},[579],"[\u002FScript\u002FEngine.Engine]\n+ActiveClassRedirects=(OldClassName=\"OceanManager\",NewClassName=\"\u002FScript\u002FOcean.OceanManager\")\n+ActiveClassRedirects=(OldClassName=\"WaveSetParameters\",NewClassName=\"\u002FScript\u002FOcean.WaveSetParameters\")\n+ActiveClassRedirects=(OldClassName=\"WaveParameter\",NewClassName=\"\u002FScript\u002FOcean.WaveParameter\")\n",[583,1287,1285],{"__ignoreMap":218},[11,1289,1290],{},"其中OldClassName为旧的类名称，不用指定Package名称，而NewClassName则必须指定Package名称。",[11,1292,1293],{},"Package名称一般就是项目的名称，如果类是定义在插件中的话，就是插件的名称。上面的格式中，Ocean就是项目的名称。",[11,1295,1296],{},"重定向配置还有一个额外的参数：",[576,1298,1301],{"className":1299,"code":1300,"language":581},[579],"+ActiveClassRedirects=(OldClassName=\"MyClass\",NewClassName=\"MyClassParent\",InstanceOnly=\"true\")\n",[583,1302,1300],{"__ignoreMap":218},[11,1304,1305],{},"可以为重定向提供一个过渡的阶段，只有类的实例会被替换成新的类，而原有的类依然继续存在。",[32,1307,1308],{"id":1308},"合并重定向",[11,1310,1311],{},"包括内容管理器自动进行的重定向在内，长期累积之下，项目中就会累积很多重定向，这个时候就需要用到清理功能。清理重定向的功能在内容管理器中就可以使用，在任何一个目录上点击右键就可以看到：",[11,1313,1314],{},[41,1315],{"alt":291,"src":1316},"\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002Fimage_thumb-12.png",[11,1318,1319],{},"同时也可以使用命令行工具进行清理",[576,1321,1324],{"className":1322,"code":1323,"language":581},[579],"UE4Editor.exe \"E:\\Ues\\Trace\" -run=FixupRedirects –testonly\n",[583,1325,1323],{"__ignoreMap":218},[11,1327,1328],{},[41,1329],{"alt":1330,"src":1331},"SNAGHTML9585f4","\u002Fwp-content\u002Fuploads\u002F2017\u002F04\u002FSNAGHTML9585f4_thumb.png",[11,1333,1334],{},"不过在有的时候还是会出现C++类重新指定失败的情况，所以一般在重定向操作之后，如果已经没有必要继续使用旧类的情况下，当时就把重定向清理掉比较好。",{"title":218,"searchDepth":219,"depth":220,"links":1336},[1337,1338],{"id":1271,"depth":219,"text":1271},{"id":1308,"depth":219,"text":1308},"2017-04-26",{"layout":235,"status":236,"published":237,"author":1341,"author_login":240,"author_email":241,"wordpress_id":1342,"wordpress_url":1343,"date_gmt":1344,"excerpt":1345},{"display_name":239,"login":240,"email":241,"url":218},1632,"\u002F\u002F?p=1632","2017-04-26 14:14:24 +0000",{"type":8,"value":1346},[1347],[11,1348,1242],{},"\u002F2017-04-26-ue4-active-class-redirects",{"title":1237,"description":1242},"_legacy\u002F2017\u002F2017-04-26-ue4-active-class-redirects",[253,1353],"ActiveClassRedirects","b-o6mKcJJtyTIAVSY5TXqiLI35aVfUs_cVLrh0ZqHR0",222,1788763183639]