[{"data":1,"prerenderedAt":1572},["ShallowReactive",2],{"page-UE4-9":3,"page-count-UE4":1571},[4,555,875,1111,1343],{"id":5,"title":6,"body":7,"date":532,"description":13,"extension":533,"meta":534,"navigation":104,"path":548,"seo":549,"stem":550,"tags":551,"__hash__":554},"blogs\u002F_legacy\u002F2017\u002F2017-06-24-unrealpak-note.md","UnrealPak的使用笔记",{"type":8,"value":9,"toc":509},"minimark",[10,14,22,27,30,33,172,175,180,183,193,197,200,203,207,210,214,217,220,224,227,230,232,236,239,242,245,249,252,254,257,260,263,266,269,272,275,279,282,285,288,291,294,297,300,303,306,314,317,323,326,332,335,344,350,353,359,362,368,371,374,377,381,389,392,396,402,405,409,412,418,421,424,427,430,433,440,443,446,449,455,458,464,467,473,476,479,485,488,491,494,497,505],[11,12,13],"p",{},"UE4的打包可以通过编辑器直接进行，但是当要实现一些特殊的目标，例如热更新等时，就需要自己使用UnrealPak进行才行。",[11,15,16,17,21],{},"当前使用UE4版本4.16，所有打包",[18,19,20],"strong",{},"仅","在Shiping模式下测试过。",[23,24,26],"h2",{"id":25},"unrealpak","UnrealPak",[11,28,29],{},"UnrealPak在整个打包过程中位于最后面的一个过程，在编辑器中打包的话可以通过输出判断打包的各个阶段。在编译、烘焙之后，如果有勾选Use Pak这个选项的话，引擎就会尝试将以上两个过程中生成的内容打包到Pak中去。",[11,31,32],{},"UnrealPak.exe位于引擎目录下Engine\u002FWin64中，运行程序，在错误提示中有给出基本的使用方法：",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-shell shiki shiki-themes github-light-high-contrast github-dark monokai","UnrealPak \u003CPakFilename> -Test\nUnrealPak \u003CPakFilename> -List\nUnrealPak \u003CPakFilename> -Extract \u003CExtractDir>\nUnrealPak \u003CPakFilename> -Create=\u003CResponseFile> [Options]\nUnrealPak \u003CPakFilename> -Dest=\u003CMountPoint>\nUnrealPak GenerateKeys=\u003CKeyFilename>\nUnrealPak GeneratePrimeTable=\u003CKeyFilename> [-TableMax=\u003CN>]\nUnrealPak \u003CPakFilename1> \u003CPakFilename2> -diff\nUnrealPak -TestEncryption\n\nOptions:\n-blocksize=\u003CBlockSize>\n-bitwindow=\u003CBitWindow>\n-compress\n-encrypt\n-order=\u003COrderingFile>\n-diff (requires 2 filenames first)\n-enginedir (specify engine dir for when using ini encryption configs)\n-projectdir (specify project dir for when using ini encryption configs)\n-encryptionini (specify ini base name to gather encryption settings from)\n-encryptindex (encrypt the pak file index, making it unusable in unrealpak without supplying the key)\n","shell","",[41,42,43,51,57,63,69,75,81,87,93,99,106,112,118,124,130,136,142,148,154,160,166],"code",{"__ignoreMap":39},[44,45,48],"span",{"class":46,"line":47},"line",1,[44,49,50],{},"UnrealPak \u003CPakFilename> -Test\n",[44,52,54],{"class":46,"line":53},2,[44,55,56],{},"UnrealPak \u003CPakFilename> -List\n",[44,58,60],{"class":46,"line":59},3,[44,61,62],{},"UnrealPak \u003CPakFilename> -Extract \u003CExtractDir>\n",[44,64,66],{"class":46,"line":65},4,[44,67,68],{},"UnrealPak \u003CPakFilename> -Create=\u003CResponseFile> [Options]\n",[44,70,72],{"class":46,"line":71},5,[44,73,74],{},"UnrealPak \u003CPakFilename> -Dest=\u003CMountPoint>\n",[44,76,78],{"class":46,"line":77},6,[44,79,80],{},"UnrealPak GenerateKeys=\u003CKeyFilename>\n",[44,82,84],{"class":46,"line":83},7,[44,85,86],{},"UnrealPak GeneratePrimeTable=\u003CKeyFilename> [-TableMax=\u003CN>]\n",[44,88,90],{"class":46,"line":89},8,[44,91,92],{},"UnrealPak \u003CPakFilename1> \u003CPakFilename2> -diff\n",[44,94,96],{"class":46,"line":95},9,[44,97,98],{},"UnrealPak -TestEncryption\n",[44,100,102],{"class":46,"line":101},10,[44,103,105],{"emptyLinePlaceholder":104},true,"\n",[44,107,109],{"class":46,"line":108},11,[44,110,111],{},"Options:\n",[44,113,115],{"class":46,"line":114},12,[44,116,117],{},"-blocksize=\u003CBlockSize>\n",[44,119,121],{"class":46,"line":120},13,[44,122,123],{},"-bitwindow=\u003CBitWindow>\n",[44,125,127],{"class":46,"line":126},14,[44,128,129],{},"-compress\n",[44,131,133],{"class":46,"line":132},15,[44,134,135],{},"-encrypt\n",[44,137,139],{"class":46,"line":138},16,[44,140,141],{},"-order=\u003COrderingFile>\n",[44,143,145],{"class":46,"line":144},17,[44,146,147],{},"-diff (requires 2 filenames first)\n",[44,149,151],{"class":46,"line":150},18,[44,152,153],{},"-enginedir (specify engine dir for when using ini encryption configs)\n",[44,155,157],{"class":46,"line":156},19,[44,158,159],{},"-projectdir (specify project dir for when using ini encryption configs)\n",[44,161,163],{"class":46,"line":162},20,[44,164,165],{},"-encryptionini (specify ini base name to gather encryption settings from)\n",[44,167,169],{"class":46,"line":168},21,[44,170,171],{},"-encryptindex (encrypt the pak file index, making it unusable in unrealpak without supplying the key)\n",[11,173,174],{},"整个程序大致的功能就是可以解压和打包Pak文件：",[176,177,179],"h3",{"id":178},"generatekeys","GenerateKeys",[11,181,182],{},"生成加密Key到文件中，RSA用于对Pak进行签名。",[184,185,186,190],"ul",{},[187,188,189],"li",{},"P：用于RSA的素数p",[187,191,192],{},"Q：用于RSA的素数q",[176,194,196],{"id":195},"generateprimetable","GeneratePrimeTable",[11,198,199],{},"生成素数表，",[11,201,202],{},"TableMax：生成表的停止（最大）数值，默认值10000",[176,204,206],{"id":205},"testencryption","TestEncryption",[11,208,209],{},"测试加密算法的执行，并不检测具体的Key和文件。",[176,211,213],{"id":212},"test","TEST",[11,215,216],{},"对Pak文件进行检测，会对每一个文件进行SHA1校验。",[11,218,219],{},"signed：Pak是否已签名",[176,221,223],{"id":222},"list","List",[11,225,226],{},"列出文件。",[11,228,229],{},"SizeFilter：文件的大小过滤器，会对大于这个大小的文件进行总Size的统计。",[11,231,219],{},[176,233,235],{"id":234},"diff","Diff",[11,237,238],{},"对比两个Pak文件",[11,240,241],{},"nouniques：通过指定nouniquesfile1、nouniquesfile2，是否列出Unique的文件",[11,243,244],{},"signed：Pak是否已签名，不能分开指定。",[176,246,248],{"id":247},"extract","Extract",[11,250,251],{},"解包。",[11,253,219],{},[176,255,256],{"id":256},"构建",[11,258,259],{},"blocksize：块大小，MB或KB单位",[11,261,262],{},"bitwindow：压缩的窗口大小，这个值越大压缩的效果越好，同时消耗的性能也越高。",[11,264,265],{},"patchpaddingalign：是否在进行Patch时启用对齐，不patch时对齐时自动的。",[11,267,268],{},"encryptindex：加密索引，使得文件索引在不提供key的情况下无法解密。",[11,270,271],{},"order：文件读取顺序列表，这个order在cook时会自动生成，一般不用自己提供。uexp会被加上序列值1 \u003C\u003C 29和ubulk会被加上1 \u003C\u003C 30。没有提供order的其他文件将获得 (1 \u003C\u003C 28)。",[11,273,274],{},"sign：对Pak进行签名的RSA的key",[276,277,278],"h4",{"id":278},"create",[11,280,281],{},"文件列表，可在其中单独指定compress和encrypt，但是如果在命令行中指定了的话，就会被强制使用到所有文件。可以是目录或是使用*通配符。",[11,283,284],{},"generatepatch：生成Patch |同时可使用 TempFiles来指定临时目录",[11,286,287],{},"compress：压缩",[11,289,290],{},"encrypt：加密",[276,292,293],{"id":293},"dest",[11,295,296],{},"替换Pak中的MountPoint。",[176,298,299],{"id":299},"加密和压缩",[11,301,302],{},"Pak采用RSA进行签名，AES进行加密，SHA1进行校验。",[11,304,305],{},"加密的流程没有测试，加密的参数可以在ini文件Encryption中进行设置，要使用ini配置的话，需要指定-encryptionini。或者，可以直接在命令行中提供加密参数：",[34,307,312],{"className":308,"code":310,"language":311},[309],"language-text","-Sign=filename\n\n","text",[41,313,310],{"__ignoreMap":39},[11,315,316],{},"或者",[34,318,321],{"className":319,"code":320,"language":311},[309],"-sign=0x123456789abcdef+0x1234567+0x12345abc\n",[41,322,320],{"__ignoreMap":39},[11,324,325],{},"其中第一个数是Exponent，第二个数是Module，第三个数是公钥的Exponent",[34,327,330],{"className":328,"code":329,"language":311},[309],"-aes=blabla\n",[41,331,329],{"__ignoreMap":39},[11,333,334],{},"来提供AES加密秘钥。",[11,336,337,338,343],{},"当前的ProjectLauncher打包，会自动添加-encryptionini，但是只要没有提供Encryption.ini，或者[",[339,340,342],"a",{"href":341},"\u002F2017-06-06-ue4-config-usage\u002F#i","Ini配置","]不正确，就不会进行加密。配置文件的内容应该是类似这样的：",[34,345,348],{"className":346,"code":347,"language":311},[309],"[Core.Encryption]\nSignPak=True\nEncryptPak=True\nrsa.publicexp=blablabla\nrsa.privateexp=blablabla\nrsa.modulus=blablabla\naes.key=blablabla\n",[41,349,347],{"__ignoreMap":39},[11,351,352],{},"由于没有实际测试过，所以不是很明确Encryption的配置能否被打包后的程序自动加载。如果出现了问题，可以检查下CoreDelegate中的：",[34,354,357],{"className":355,"code":356,"language":311},[309],"static FPakEncryptionKeyDelegate& GetPakEncryptionKeyDelegate();\nstatic FPakSigningKeysDelegate& GetPakSigningKeysDelegate();\n",[41,358,356],{"__ignoreMap":39},[11,360,361],{},"引擎在Mount时会从这两个Delegate中获取加密相关的信息，在CoreDelegate的Cpp中有提供",[34,363,366],{"className":364,"code":365,"language":311},[309],"void RegisterEncryptionKey(const char* InEncryptionKey)\n{\n  FCoreDelegates::GetPakEncryptionKeyDelegate().BindLambda([InEncryptionKey]() { return InEncryptionKey; });\n}\n\nvoid RegisterPakSigningKeys(const char* InExponent, const char* InModulus)\n{\n  static FString Exponent(ANSI_TO_TCHAR(InExponent));\n  static FString Modulus(ANSI_TO_TCHAR(InModulus));\n\nFCoreDelegates::GetPakSigningKeysDelegate().BindLambda([](FString& OutExponent, FString& OutModulus)\n{\n  OutExponent = Exponent;\n  OutModulus = Modulus;\n});\n}\n",[41,367,365],{"__ignoreMap":39},[11,369,370],{},"如果没有办法成功注册解密的话，可以尝试模仿引擎代码进行注册来调试一下。",[11,372,373],{},"不过事实上这些功能如果只是打包的话基本不用深究，在使用Project Launcer进行打包时，可以看到编辑器对UnrealPak的调用，将其复制出来，然后进行相应的修改就可以了。",[11,375,376],{},"在进行测试的时候需要注意，UE4对于Asset的加载是有要求的，如果是Shiping烘焙的内容，是无法在编辑器中加载的，必须统一内容的打包格式。",[23,378,380],{"id":379},"mount","Mount",[11,382,383,384,388],{},"Pak在运行时通过Mount将内容读取到游戏中，如果不希望Pak文件被自动加载的话，可以不将其放到[",[339,385,387],{"href":386},"\u002F2017-05-01-ue4-patch-release-dlc\u002F#Maps","自动加载目录","]中。",[11,390,391],{},"手动加载Pak文件时，通常采用的Mount方法有两种。",[176,393,395],{"id":394},"手动mount","手动Mount",[34,397,400],{"className":398,"code":399,"language":311},[309],"EL_LOG(TEXT(\"[AShipIssueGameModeBase] LoadPakMount(): %s\"), *PakPath);\nFString SaveContentDir = PakPath;\nUE_LOG(LogTemp, Log, TEXT(\"[AShipIssueGameModeBase]  ----------- LoadPak: %s --------------\"), *SaveContentDir);\n\n\u002F\u002F获取当前使用的平台,这里使用的是WIN64平台\nIPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();\n\u002F\u002F初始化PakPlatformFile\nFPakPlatformFile* PakPlatformFile = new FPakPlatformFile();\nPakPlatformFile->Initialize(&PlatformFile, TEXT(\"\"));\nFPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);\n\n\u002F\u002F获取Pak文件\nFPakFile PakFile(&PlatformFile, *SaveContentDir, false);\n\n\u002F\u002F设置pak文件的Mount点.\nFString MountPoint(\"..\u002F..\u002F..\u002F[ProjectName]\u002F\");\nUE_LOG(LogTemp, Log, TEXT(\"[AShipIssueGameModeBase] - Mount Path: %s\"), *MountPoint);\nEL_LOG(TEXT(\"[AShipIssueGameModeBase] Mount Path: %s\"), *MountPoint);\n\nPakFile.SetMountPoint(*MountPoint);\n\u002F\u002F对pak文件mount到前面设定的MountPoint\nif (PakPlatformFile->Mount(*SaveContentDir, 0, *MountPoint))\n{\n  UE_LOG(LogTemp, Log, TEXT(\"[AShipIssueGameModeBase] - Mount Success\"));\n  EL_LOG(TEXT(\"[AShipIssueGameModeBase] Mount Success\"));\n\n}\n",[41,401,399],{"__ignoreMap":39},[11,403,404],{},"这个方法可以手动指定MountPoint，但是通常情况下，除非很确定自己打包了什么，否则很容易丢失各个Asset之间的引用。",[176,406,408],{"id":407},"coredelegate","CoreDelegate",[11,410,411],{},"这个是最近的版本添加的帮助函数，比上面的方法更加的简单实用。",[34,413,416],{"className":414,"code":415,"language":311},[309],"if (FCoreDelegates::OnMountPak.IsBound())\n{\n  if (FCoreDelegates::OnMountPak.Execute(PakPath, 4, nullptr))\n  {\n     EL_LOG(TEXT(\"[AShipIssueGameModeBase] LoadPakDelegate(): OnMountPak.Execute Successful.\"));\n     GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT(\"OnMountPak.Execute Successful.\"));\n  }\n  else\n  {\n    EL_LOG(TEXT(\"[AShipIssueGameModeBase] LoadPakDelegate(): OnMountPak.Execute Falied.\"));\n    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT(\"OnMountPak.Execute Falied.\"));\n  }\n}\nelse\n{\n  EL_LOG(TEXT(\"[AShipIssueGameModeBase] LoadPakDelegate(): OnMountPak.IsBound() Falied\"));\n  GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT(\"OnMountPak.IsBound() Falied\"));\n}\n",[41,417,415],{"__ignoreMap":39},[11,419,420],{},"使用这个方法会将内容Mount到内容根目录，引擎内部加载Pak文件也是使用的这个方法。",[23,422,423],{"id":423},"路径与引用",[11,425,426],{},"一般情况下使用同一个项目打包的Pak文件，只要打包正确，进行Mount都不会有什么问题。",[11,428,429],{},"而如果使用其他项目进行打包的话，可能会存在一些引用丢失的问题。通常的表现是，使用Mount后的路径可以打开地图，但是地图内物品的材质等关联属性全部都丢失了。",[11,431,432],{},"这个问题通常都是路径问题引起的，另外，在Cook目录中会有AssetRegistry，这个文件是UE用来保存各个Asset之间的引用的，在网上有看到Mount时要自己加载并注册的描述，但是目前版本测试下似乎是会自动加载的。至少在没有主动加载AssetRegistry的情况下，引用已经是正常的了，但是如果出现了引用丢失的问题，可以从这个方面进行一下检查。而且使用CoreDelegate进行Mount的话，是不需要关心这个的。",[11,434,435,436,439],{},"在打包时主要的路径问题来自于打包时的处理机制，UnrealPak会尝试从所有待打包的文件中提取公共的目录作为根目录。而这个根目录之后会被挂在MountPoint之下，那么如果配置有不正确的话，必然会丢失引用。如果引用丢失了的话，对打包的根目录检查也是必要的。在使用",[41,437,438],{},"-create=\u003CResponsFile>","进行打包时，可以在每个文件列的后面指定打包的目标目录，可以一定程度的上解决这个问题。",[176,441,442],{"id":442},"实际使用",[11,444,445],{},"注意：这里记录的是目前项目中使用的路径，并不代表这是一个“好”的方法。因为UnrealPak自主打包无论如何都不会优雅，如果没有紧急的打包需求，建议等官方的Chunk机制等一系列打包功能完善之后直接使用~",[11,447,448],{},"首先，对目标项目ShipIssue进行打包，从Log中拷贝UnrealPak的记录：",[34,450,453],{"className":451,"code":452,"language":311},[309],"D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64\\UnrealPak.exe F:\\Ue_Patch\\1.0_nomap\\WindowsNoEditor\\ShipIssue\\Content\\Paks\\ShipIssue-WindowsNoEditor.pak -create=\"C:\\Users\\Administrator\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakList_ShipIssue-WindowsNoEditor.txt\" -encryptionini -enginedir=\"D:\\Code\\UE_4.16\\Engine\" -projectdir=\"E:\\GameDev\\ShipIssue\" -platform=Windows -abslog=\"C:\\Users\\Administrator\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakLog_ShipIssue-WindowsNoEditor.log\" -installed -order=E:\\GameDev\\ShipIssue\\Build\\WindowsNoEditor\\FileOpenOrder\\CookerOpenOrder.log -UTF8Output -multiprocess -patchpaddingalign=2048\n",[41,454,452],{"__ignoreMap":39},[11,456,457],{},"然后，将要打包的项目FreePatch进行Cook之后，对拷贝的命令修改：",[34,459,462],{"className":460,"code":461,"language":311},[309],"D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64\\UnrealPak.exe F:\\Ue_Patch\\1.0_nomap\\WindowsNoEditor\\ShipIssue\\Content\\Paks\\Free.pak -create=\"E:\\PakScript\\list.txt\" -encryptionini -enginedir=\"D:\\Code\\UE_4.16\\Engine\" -projectdir=\"E:\\GameDev\\ShipIssue\" -platform=Windows -abslog=\"C:\\Users\\Administrator\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakLog_ShipIssue-WindowsNoEditor.log\" -installed -order=E:\\GameDev\\FreePatch\\Build\\WindowsNoEditor\\FileOpenOrder\\CookerOpenOrder.log -UTF8Output -multiprocess -patchpaddingalign=2048\n",[41,463,461],{"__ignoreMap":39},[11,465,466],{},"Order指令的文件可以直接使用Cook出来的，list.txt直接写：",[34,468,471],{"className":469,"code":470,"language":311},[309],"\"E:\\GameDev\\FreePatch\\Saved\\Cooked\\WindowsNoEditor\\FreePatch\\*\" \"..\u002F..\u002F..\u002FShipIssue\u002F*\" –compress\n",[41,472,470],{"__ignoreMap":39},[11,474,475],{},"目标目录写成目标项目的目录，这样的话打包出来的pak文件在自动加载和使用CoreDelegate加载后都能保持正确的引用。",[11,477,478],{},"如果保留原项目名",[34,480,483],{"className":481,"code":482,"language":311},[309],"\"E:\\GameDev\\FreePatch\\Saved\\Cooked\\WindowsNoEditor\\FreePatch\\*\" \"..\u002F..\u002F..\u002FFreePatch\u002F*\" –compress\n",[41,484,482],{"__ignoreMap":39},[11,486,487],{},"需要Mount时自己将MountPoint指定到..\u002F..\u002F..\u002FShipIssue\u002F，自动加载和CoreDelegate加载会加载到..\u002F..\u002F..\u002FFreePatch\u002F导致无法读取到地图中物体引用的材质。",[11,489,490],{},"因此并不推荐这样做~",[11,492,493],{},"通常情况下，只要mount之后的路径在\u002FShipIssue\u002F下的结构与原本在Content\u002F下的结构相同，材质之类的引用就不会丢失。丢失的情况，一般从路径方面检查下先比较好。",[11,495,496],{},"更新：由于Pak的加载确实有些迷，经常会有朋友发邮件或者留言来问我。但是从打包到加载的过程中的可变量太多，我也无法准确的知道每个人遇到的问题。所以在这里将测试打包用到的代码分离成一个插件。",[11,498,499,500,504],{},"其实插件本身并不复杂，只是在使用UFS的API遍历访问而已。主要的作用是可以方便对加载过程的理解和问题的排查。详情请参考[",[339,501,503],{"href":502},"\u002Fpage\u002Fue4-pak-file-view\u002F","UE4文件查看插件","]。",[506,507,508],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":39,"searchDepth":53,"depth":59,"links":510},[511,525,529],{"id":25,"depth":53,"text":26,"children":512},[513,514,515,516,517,518,519,520,524],{"id":178,"depth":59,"text":179},{"id":195,"depth":59,"text":196},{"id":205,"depth":59,"text":206},{"id":212,"depth":59,"text":213},{"id":222,"depth":59,"text":223},{"id":234,"depth":59,"text":235},{"id":247,"depth":59,"text":248},{"id":256,"depth":59,"text":256,"children":521},[522,523],{"id":278,"depth":65,"text":278},{"id":293,"depth":65,"text":293},{"id":299,"depth":59,"text":299},{"id":379,"depth":53,"text":380,"children":526},[527,528],{"id":394,"depth":59,"text":395},{"id":407,"depth":59,"text":408},{"id":423,"depth":53,"text":423,"children":530},[531],{"id":442,"depth":59,"text":442},"2017-06-24","md",{"layout":535,"status":536,"published":104,"author":537,"author_login":539,"author_email":540,"wordpress_id":541,"wordpress_url":542,"date_gmt":543,"excerpt":544},"post","publish",{"display_name":538,"login":539,"email":540,"url":39},"风铃","flinkor","flinkor@foxmail.com",1790,"\u002F\u002F?p=1790","2017-06-24 11:37:17 +0000",{"type":8,"value":545},[546],[11,547,13],{},"\u002F2017-06-24-unrealpak-note",{"title":6,"description":13},"_legacy\u002F2017\u002F2017-06-24-unrealpak-note",[552,26,553],"UE4","Pak","Jr-XOewnXJ3-UJQa19DQu02xnktkiNhN_su7wcAU86Y",{"id":556,"title":557,"body":558,"date":859,"description":562,"extension":533,"meta":860,"navigation":104,"path":869,"seo":870,"stem":871,"tags":872,"__hash__":874},"blogs\u002F_legacy\u002F2017\u002F2017-06-06-ue4-config-usage.md","UE4中Config的使用",{"type":8,"value":559,"toc":852},[560,563,566,569,572,575,611,614,655,658,667,670,673,679,682,688,691,697,700,703,706,712,723,726,729,735,738,741,761,768,771,774,777,780,783,786,789,795,798,801,807,810,816,819,822,825,831,834,837,840,843],[11,561,562],{},"UE4中本身有一套非常成熟的INI文件配置机制，对于简单的属性配置，可以直接进行借用。",[11,564,565],{},"当前使用的UE4版本为4.15.2。",[23,567,568],{"id":568},"引擎配置",[11,570,571],{},"整个Config机制在引擎中最常见的地方就是引擎的配置本身了，项目配置与引擎配置，Localize的配置……这些都是通过这个机制进行的。",[11,573,574],{},"引擎自带的配置分类有以下这些：",[576,577,578,581,584,587,590,593,596,599,602,605,608],"blockquote",{},[11,579,580],{},"Compat（兼容性）",[11,582,583],{},"DeviceProfiles（设备概述文件）",[11,585,586],{},"Editor（编辑器）",[11,588,589],{},"EditorGameAgnostic（编辑器游戏不可知论）",[11,591,592],{},"EditorKeyBindings（编辑器按键绑定）",[11,594,595],{},"EditorUserSettings（编辑器用户设置）",[11,597,598],{},"Engine(引擎)",[11,600,601],{},"Game(游戏)",[11,603,604],{},"Input（输入）",[11,606,607],{},"Lightmass",[11,609,610],{},"Scalability（可扩展性）",[11,612,613],{},"配置文件是有加载优先的，按照官方文档提供的顺序，越靠后的值会覆盖前面的值。",[576,615,616,619,622,632,638,647],{},[11,617,618],{},"Engine\u002FConfig\u002FBase.ini",[11,620,621],{},"Engine\u002FConfig\u002FBaseEngine.ini",[11,623,624,625,628,629,631],{},"Engine\u002FConfig\u002F",[44,626,627],{},"Platform","\u002F",[44,630,627],{},"Engine.ini",[11,633,634,637],{},[44,635,636],{},"ProjectDirectory","\u002FConfig\u002FDefaultEngine.ini",[11,639,640,642,643,628,645,631],{},[44,641,636],{},"\u002FConfig\u002F",[44,644,627],{},[44,646,627],{},[11,648,649,651,652,654],{},[44,650,636],{},"\u002FSaved\u002FConfig\u002F",[44,653,627],{},"\u002FEngine.ini",[11,656,657],{},"这个加载次序是以Engine配置为基础的。",[11,659,660,661,504],{},"关于这部分的详细可以参照[",[339,662,666],{"href":663,"rel":664},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FProgramming\u002FBasics\u002FConfigurationFiles\u002Findex.html",[665],"nofollow","官方文档",[23,668,669],{"id":669},"自主调用",[11,671,672],{},"使用GConfig就可以对这个配置系统中的值进行查询和写入，要对配置进行读取的话可以使用：",[34,674,677],{"className":675,"code":676,"language":311},[309],"if(!GConfig) return;\n\nFString ValueReceived;\n  GConfig->GetString(\n  TEXT(\"\u002FScript\u002FEngine.WorldInfo\"),\n  TEXT(\"GlobalDefaultGameType\"),\n  ValueReceived,\n  GGameIni\n);\n",[41,678,676],{"__ignoreMap":39},[11,680,681],{},"而写入的话，可以使用：",[34,683,686],{"className":684,"code":685,"language":311},[309],"if (!GConfig) return;\nGConfig->SetInt(\n  TEXT(\"sectionname\"),\n  TEXT(\"key\"),\n  100,\n  GGameUserSettingsIni\n  );\nGConfig->Flush(false, GGameUserSettingsIni);\n",[41,687,685],{"__ignoreMap":39},[11,689,690],{},"这里使用的Get\u002FSet是一系列函数，对应引擎内部的不同值，第四个参数是配置的名称，与上面给出的配置分类是对应的，应该，没有仔细的考证过。可以看到GGameUserSettingsIni附近有很多这样的定义：",[34,692,695],{"className":693,"code":694,"language":311},[309],"FString                GEngineIni;                                                    \u002F* Engine ini filename *\u002F\n\n\u002F** Editor ini file locations - stored per engine version (shared across all projects). Migrated between versions on first run. *\u002F\nFString                GEditorIni;                                                    \u002F* Editor ini filename *\u002F\nFString                GEditorKeyBindingsIni;                                        \u002F* Editor Key Bindings ini file *\u002F\nFString                GEditorLayoutIni;                                            \u002F* Editor UI Layout ini filename *\u002F\nFString                GEditorSettingsIni;                                            \u002F* Editor Settings ini filename *\u002F\n\n\u002F** Editor per-project ini files - stored per project. *\u002F\nFString                GEditorPerProjectIni;                                        \u002F* Editor User Settings ini filename *\u002F\n\nFString                GCompatIni;\nFString                GLightmassIni;                                                \u002F* Lightmass settings ini filename *\u002F\nFString                GScalabilityIni;                                            \u002F* Scalability settings ini filename *\u002F\nFString                GHardwareIni;                                                \u002F* Hardware ini filename *\u002F\nFString                GInputIni;                                                    \u002F* Input ini filename *\u002F\nFString                GGameIni;                                                    \u002F* Game ini filename *\u002F\nFString                GGameUserSettingsIni;                                        \u002F* User Game Settings ini filename *\u002F\n",[41,696,694],{"__ignoreMap":39},[11,698,699],{},"其实这种用法，使用起来相对有些麻烦，而且会把自己的配置和引擎的配置混在一起，其实还有更加简单的使用这个配置的方法：",[23,701,702],{"id":702},"扩展使用",[11,704,705],{},"这个特性是可以扩展给自己定义的类使用的，在UClass定义时制定Config即可，像是这样的感觉：",[34,707,710],{"className":708,"code":709,"language":311},[309],"UCLASS(config=GameUserSettings, configdonotcheckdefaults)\nclass ENGINE_API UGameUserSettings : public UObject\n",[41,711,709],{"__ignoreMap":39},[11,713,714,715,718,719,722],{},"其实上面那些自带的引擎配置就是在引擎中预先定义好的",[44,716,717],{},"名称","-",[44,720,721],{},"配置文件名","对应组。",[11,724,725],{},"这里面在定义时，config=custom，这样自己定义配置文件名称也是可以的。如果不想自己的配置和引擎的配置混在一起变得乱七八糟的话，这是一个很好的选择。",[11,727,728],{},"这样的好处是所有标记为UProperty的属性加上config标记都会被自动载入，在执行SaveConfig后就可以直接保存，不需要和配置的逻辑打交道。定义时就像这样的感觉：",[34,730,733],{"className":731,"code":732,"language":311},[309],"UPROPERTY(config, EditAnywhere, Category=\"MouseProperties”)\nuint32 bEnableFOVScaling:1;\n",[41,734,732],{"__ignoreMap":39},[11,736,737],{},"在文件名的分配上，如果使用custom的话，配置文件就会被保存到custom.ini的命名规则下。如果一时之间找不到配置文件，可以使用这个文件名进行搜索。",[11,739,740],{},"这一系列的配置还有其他几个选项：",[576,742,743,746,749,752,755,758],{},[11,744,745],{},"perObjectConfig",[11,747,748],{},"使得配置变为针对每个Object的实例，而不是每个Class存一个配置块。",[11,750,751],{},"configdonotcheckdefaults",[11,753,754],{},"配置了这个的话，config在读取的时候就不会去读取default配置。",[11,756,757],{},"defaultconfig",[11,759,760],{},"配置只保存在default中",[11,762,763,764,767],{},"这里有一个概念就是Default，Default配置的读取是比较靠前的，通常保存在项目目录Config\u002F",[44,765,766],{},"Custom","Default.ini中。这里有一个在测试时需要注意的，如果SaveConfig的值与Default值相同的话，那么就会不进行保存，该行配置会消失，因为与默认值一样了。",[11,769,770],{},"在进行配置文件操作和设定时，可以使用UpdateDefaultConfigFile()来写入到default值，而通常的配置可以使用SaveConfig()进行保存，因为SaveConfig是会自动进行Flush的，而另一个UpdateGlobal ConfigFile则局限性较强，但它可以确保写入路径是指向用户配置的。",[11,772,773],{},"要注意的是，如果在Shipping打包模式下，那么可以让用户和我们自己进行配置的ini文件将不会出现在项目目录中个，而是在\"用户目录\\AppData\\Local\\rg_unreal\\Saved\\Config\\WindowsNoEditor[custom].ini\"中。",[11,775,776],{},"如果觉得这样有些Low的话，我们就需要绕回去：",[23,778,779],{"id":779},"自定义路径",[11,781,782],{},"仔细查看Config系统的源码，我们可以看到，ini的加载是在UObject中进行指定的。如果没有定义PerObjectConfig的话，配置是在CDO阶段就完成了的。如果定义了PerObject的话则会在UObject:: PostLoad中进行配置加载。",[11,784,785],{},"但是系统本身的GetConfigName是无法被重载的，好在引擎有暴露其他的接口，我们要对其使用只要自己在BeginPlay之类的事件中自己进行读写就可以了。",[11,787,788],{},"其实要使用的函数在上面已经用到了，只是在调用的时候使用的是默认参数罢了。",[34,790,793],{"className":791,"code":792,"language":311},[309],"SaveConfig(CPF_Config, *ConfPath);\n",[41,794,792],{"__ignoreMap":39},[11,796,797],{},"这样调用的话就可以将当前类中的配置保存到指定的路径去了，不用指定后缀名Ini也是可以的。",[11,799,800],{},"不过，出于保险起见，最好是在Save之后，刷新一下缓存",[34,802,805],{"className":803,"code":804,"language":311},[309],"GConfig->Flush(false, ConfPath)\n",[41,806,804],{"__ignoreMap":39},[11,808,809],{},"要读取的话也是同理，先刷新缓存",[34,811,814],{"className":812,"code":813,"language":311},[309],"GConfig->Flush(true, ConfPath)\n",[41,815,813],{"__ignoreMap":39},[11,817,818],{},"其实如果配置的读写都是在引擎内完成的话，是没必要在读取的时候刷缓存的。",[11,820,821],{},"但如果有在引擎外部修改配置文件，并希望配置“实时”的反映到读取中的话，就需要在读取前刷新一下缓存。",[11,823,824],{},"读取的话使用",[34,826,829],{"className":827,"code":828,"language":311},[309],"ReloadConfig(NULL, *ConfPath)\n",[41,830,828],{"__ignoreMap":39},[11,832,833],{},"就可以了，这里使用到的ConfPath都是FString。",[23,835,836],{"id":836},"总结",[11,838,839],{},"基本上配置存取使用官方的配置类就可以了，这里有一点很强大的是，似乎所有可以UPROPERTY化的引擎定义变量都可以写入到Config中，已经测试过TArray和TMap可以正常的进行读写。",[11,841,842],{},"但是像是UObject这类的并没有进行测试……不过引擎的配置中有大量的使用UAsset的引用，应当是毫无问题的。",[11,844,845,846,851],{},"不过，配置文件虽然有读写功能，但是它的定位本身并不适合用来存档。如果有这方面的需求请使用[",[339,847,850],{"href":848,"rel":849},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FGameplay\u002FSaveGame\u002Findex.html",[665],"SaveGame类","]，蓝图与C++皆可使用。",{"title":39,"searchDepth":53,"depth":59,"links":853},[854,855,856,857,858],{"id":568,"depth":53,"text":568},{"id":669,"depth":53,"text":669},{"id":702,"depth":53,"text":702},{"id":779,"depth":53,"text":779},{"id":836,"depth":53,"text":836},"2017-06-06",{"layout":535,"status":536,"published":104,"author":861,"author_login":539,"author_email":540,"wordpress_id":862,"wordpress_url":863,"date_gmt":864,"excerpt":865},{"display_name":538,"login":539,"email":540,"url":39},1777,"\u002F\u002F?p=1777","2017-06-06 12:12:22 +0000",{"type":8,"value":866},[867],[11,868,562],{},"\u002F2017-06-06-ue4-config-usage",{"title":557,"description":562},"_legacy\u002F2017\u002F2017-06-06-ue4-config-usage",[552,873],"Config","5PE0D-8QY1nKGtyz-G-TzQvrRF7I9D4LT4XxU3vOAks",{"id":876,"title":877,"body":878,"date":1096,"description":882,"extension":533,"meta":1097,"navigation":104,"path":1106,"seo":1107,"stem":1108,"tags":1109,"__hash__":1110},"blogs\u002F_legacy\u002F2017\u002F2017-06-05-ue4-transition-log.md","UE4项目迁移笔记",{"type":8,"value":879,"toc":1091},[880,883,886,889,893,896,902,905,908,914,917,923,926,929,933,936,939,942,948,951,957,960,963,966,972,975,981,984,990,993,999,1002,1005,1009,1012,1015,1021,1024,1027,1036,1039,1046,1049,1052,1058,1061,1064,1067,1073,1076,1082,1085,1088],[11,881,882],{},"UE4本身的版本升级比较频繁，这就会导致有时候手里的或是网上下载的项目需要进行版本迁移。",[11,884,885],{},"通常情况下，如果是在小的版本之间迁移，尤其是跟着官方的步伐进行更新的话，都不会遇到什么大问题。但是如果在现在版本是4.16的情况下，要对4.7版本的项目进行迁移的话，就会有很多问题。",[11,887,888],{},"这次遇到的问题就是从网上下载的示例项目版本太旧，需要进行大的版本迁移。原本以为不会有什么太多麻烦，不想却还是花了很多时间，因此在这里记录一下。",[23,890,892],{"id":891},"build-rules","Build Rules",[11,894,895],{},"对项目进行编译，非常幸运，首先只遇到了几个Warning：",[34,897,900],{"className":898,"code":899,"language":311},[309],"1>E:\\Ues\\GAS\\Source\\GAS\\GAS.Build.cs : warning : Module constructors should take a ReadOnlyTargetRules argument (rather than a TargetInfo argument) and pass it to the base class constructor from 4.15 onwards. Please update the method signature.\n1>E:\\Ues\\GAS\\Source\\GAS.Target.cs : warning : SetupBinaries() is deprecated in the 4.16 release. From the constructor in your .target.cs file, use ExtraModuleNames.Add(\"Foo\") to add modules to your target, or set LaunchModuleName = \"Foo\" to override the name of the launch module for program targets.\n1>E:\\Ues\\GAS\\Source\\GASEditor.Target.cs : warning : SetupBinaries() is deprecated in the 4.16 release. From the constructor in your .target.cs file, use ExtraModuleNames.Add(\"Foo\") to add modules to your target, or set LaunchModuleName = \"Foo\" to override the name of the launch module for program targets.\n",[41,901,899],{"__ignoreMap":39},[11,903,904],{},"UE4最近的两次版本升级中对BuildRule进行了变更，所以在这里只要按照提示进行修改就可以了。只是官方的提示多少有些简略，实际操作是类似这样的。",[11,906,907],{},"*.build.cs",[34,909,912],{"className":910,"code":911,"language":311},[309],"public class GAS : ModuleRules\n{\n-    public GAS(TargetInfo Target)\n+    public GAS(ReadOnlyTargetRules Target) : base(Target)\n",[41,913,911],{"__ignoreMap":39},[11,915,916],{},"*.Target.cs",[34,918,921],{"className":919,"code":920,"language":311},[309],"public class GASTarget : TargetRules\n{\n-    public GASTarget(TargetInfo Target)\n+    public    GASTarget(TargetInfo Target) : base(Target)\n     {\n        Type = TargetType.Game;\n-    }\n-\n-    \u002F\u002F\n-    \u002F\u002F TargetRules interface.\n-    \u002F\u002F\n-\n-    public override void SetupBinaries(\n-          TargetInfo Target,\n-          ref List\u003CUEBuildBinaryConfiguration> OutBuildBinaryConfigurations,\n-          ref List\u003Cstring> OutExtraModuleNames\n-          )\n-    {\n-          OutExtraModuleNames.Add(\"GAS\");\n+          ExtraModuleNames.Add(\"GAS\");\n",[41,922,920],{"__ignoreMap":39},[11,924,925],{},"要留意的是，TargetRule有两个配置文件，一个是给Game的一个是给Editor的。",[11,927,928],{},"改了之后就没有提示了。",[23,930,932],{"id":931},"iwyu","IWYU",[11,934,935],{},"既然升级了BuildRules，那就自然会要使用官方在4.15新推出的号称减少50%编译时间的IWYU了。",[11,937,938],{},"这个技术似乎是优化了预编译头的处理机制，但是使用起来需要自己进行定义和设置，并不是升到4.15以上就能全面享用的优势呢。",[11,940,941],{},"首先要做的是到*.build.cs中，在ModuleRules中添加一行，类似这样：",[34,943,946],{"className":944,"code":945,"language":311},[309],"\u002F\u002F Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.\n\nusing UnrealBuildTool;\n\npublic class GAS : ModuleRules\n{\n    public GAS(ReadOnlyTargetRules Target) : base(Target)\n    {\n        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;\n\n       \u002F\u002F Some other code def\n\n    }\n}\n",[41,947,945],{"__ignoreMap":39},[11,949,950],{},"添加这行修改预编译头机制后，编译必然会遇到很多类似这样的错误：",[34,952,955],{"className":953,"code":954,"language":311},[309],"1>E:\\Ues\\GAS\\Source\\GAS\\DamageExecution.cpp(1): error : Expected DamageExecution.h to be first header included.\n1>E:\\Ues\\GAS\\Source\\GAS\\GASAttributeSet.cpp(1): error : Expected GASAttributeSet.h to be first header included.\n1>E:\\Ues\\GAS\\Source\\GAS\\GASBlueprintLibrary.cpp(1): error : Expected GASBlueprintLibrary.h to be first header included.\n",[41,956,954],{"__ignoreMap":39},[11,958,959],{},"新的PCH机制要求cpp文件必须首先包含自己的头文件，按照提示一个一个对源文件进行修改就好了。",[11,961,962],{},"此外还会遇到很多类型未定义以及由此引发的其他错误，如果有VA的话，可以对应着进行添加包含。要注意的是，连FString这样的基础类型都会有这个问题，所以还是颇为防不胜防。",[11,964,965],{},"官方推荐的是在项目的头文件中包含",[34,967,970],{"className":968,"code":969,"language":311},[309],"#include “CoreMinimal.h”\n",[41,971,969],{"__ignoreMap":39},[11,973,974],{},"当然必要的时候可能需要包含",[34,976,979],{"className":977,"code":978,"language":311},[309],"#include “EngineMinimal.h”\n",[41,980,978],{"__ignoreMap":39},[11,982,983],{},"如果项目中使用到了UEngine的话，可以选择包含",[34,985,988],{"className":986,"code":987,"language":311},[309],"#include “Engine\u002FEngine.h”\n",[41,989,987],{"__ignoreMap":39},[11,991,992],{},"但是，实际上，如果对引擎比较深的地方的类进行了继承的话，最后还是得包含",[34,994,997],{"className":995,"code":996,"language":311},[309],"#include \"Engine.h\"\n",[41,998,996],{"__ignoreMap":39},[11,1000,1001],{},"要不然可能会被报错到引擎的源代码里面去。",[11,1003,1004],{},"进行包含调整之后，基本就编译通过了。",[23,1006,1008],{"id":1007},"load-module-error","Load Module Error",[11,1010,1011],{},"原本以为编译通过了就万事大吉了，没想到在运行项目时却遇到了无法打开的问题……",[11,1013,1014],{},"使用VS进行调试运行，会看到这样的错误：",[34,1016,1019],{"className":1017,"code":1018,"language":311},[309],"[2017.06.04-02.48.31:217][ 0]LogModuleManager:Warning: ModuleManager: Unable to load module 'E:\u002FUes\u002FGAS\u002FBinaries\u002FWin64\u002FUE4Editor-GAS-Win64-DebugGame.dll' because the file couldn't be loaded by the OS.\n",[41,1020,1018],{"__ignoreMap":39},[11,1022,1023],{},"首先当然是怀疑dll文件不存在，但是实际上dll文件是存在的，那么问题出在哪里了呢？",[11,1025,1026],{},"求助万能的Google，终于找到了调试的方法。",[11,1028,1029,1030,1035],{},"这个时候需要使用微软官方的Debugging Tools for Windows，按照微软官方描述该工具被包含在WDK和Windows SDK中，因此直接",[339,1031,1034],{"href":1032,"rel":1033},"http:\u002F\u002Fgo.microsoft.com\u002Ffwlink\u002Fp?LinkID=271979",[665],"install the Windows SDK","，在安装的时候只勾选Debugging Tools for Windows就好了。",[11,1037,1038],{},"安装完成之后打开其中的一个名为Global Flags的工具，进行配置：",[11,1040,1041],{},[1042,1043],"img",{"alt":1044,"src":1045},"clip_image001","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image001_thumb-1.png",[11,1047,1048],{},"只要选择Show Loader Snaps就好了，保存选项，重启电脑。",[11,1050,1051],{},"然后重新在VS中调试运行项目，在上一次遇到错误的地方就可以看到：",[34,1053,1056],{"className":1054,"code":1055,"language":311},[309],"2264:05b0 @ 00793859 - LdrpSearchPath - ENTER: DLL name: UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793859 - LdrpComputeLazyDllPath - INFO: DLL search path computed: D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64;E:\u002FUes\u002FGAS\u002FBinaries\u002FWin64;C:\\Windows\\SYSTEM32;C:\\Windows\\system;C:\\Windows;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;D:\\Tools\\Git\\cmd;C:\\Program Files (x86)\\Windows Live\\Shared;D:\\Tools\\SVN\\bin;D:\\Code\\Python\\Scripts\\;D:\\Code\\Python\\;C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\WindowsApps;;D:\\Tools\\Microsoft VS Code\\bin\n2264:05b0 @ 00793859 - LdrpResolveDllName - ENTER: DLL name: D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793859 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793859 - LdrpResolveDllName - ENTER: DLL name: E:\u002FUes\u002FGAS\u002FBinaries\u002FWin64\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793859 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793859 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\SYSTEM32\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793859 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793859 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\system\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793859 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793859 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\system32\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\System32\\Wbem\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: D:\\Tools\\Git\\cmd\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Program Files (x86)\\Windows Live\\Shared\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: D:\\Tools\\SVN\\bin\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: D:\\Code\\Python\\Scripts\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: D:\\Code\\Python\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\WindowsApps\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpResolveDllName - ENTER: DLL name: D:\\Tools\\Microsoft VS Code\\bin\\UE4Editor-GameplayAbilities.dll\n2264:05b0 @ 00793875 - LdrpResolveDllName - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpSearchPath - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrpProcessWork - ERROR: Unable to load DLL: \"UE4Editor-GameplayAbilities.dll\", Parent Module: \"E:\\Ues\\GAS\\Binaries\\Win64\\UE4Editor-GAS.dll\", Status: 0xc0000135\n“UE4Editor.exe”(Win32): 已卸载“E:\\Ues\\GAS\\Binaries\\Win64\\UE4Editor-GAS.dll”\n2264:05b0 @ 00793875 - LdrpLoadDllInternal - RETURN: Status: 0xc0000135\n2264:05b0 @ 00793875 - LdrLoadDll - RETURN: Status: 0xc0000135\n[2017.06.04-03.19.55:171][ 0]LogModuleManager:Warning: ModuleManager: Unable to load module 'E:\u002FUes\u002FGAS\u002FBinaries\u002FWin64\u002FUE4Editor-GAS.dll' because the file couldn't be loaded by the OS.\n",[41,1057,1055],{"__ignoreMap":39},[11,1059,1060],{},"错误原因原来是UE4Editor-GameplayAbilities.dll找不到了，但是这个是引擎提供的内容，为什么会找不到呢？",[11,1062,1063],{},"费了一阵脑筋之后才想起来，似乎从某个版本开始，GamePlayAbility由引擎的Module转变为了Plugin，目的是为了避免不需要这个系统的项目包含不必要的内容。",[11,1065,1066],{},"因此直接对项目文件进行编辑，将下面的内容：",[34,1068,1071],{"className":1069,"code":1070,"language":311},[309],"{\n    \"FileVersion\": 3,\n    \"EngineAssociation\": \"\",\n    \"Category\": \"\",\n    \"Description\": \"\",\n    \"Modules\": [\n    {\n        \"Name\": \"GAS\",\n        \"Type\": \"Runtime\",\n        \"LoadingPhase\": \"Default\",\n        \"AdditionalDependencies\": [\n            \"GameplayAbilities\",\n            \"Engine\"\n        ]\n    }\n    ]\n\n}\n",[41,1072,1070],{"__ignoreMap":39},[11,1074,1075],{},"改为：",[34,1077,1080],{"className":1078,"code":1079,"language":311},[309],"{\n    \"FileVersion\": 3,\n    \"EngineAssociation\": \"4.16\",\n    \"Category\": \"\",\n    \"Description\": \"\",\n    \"Modules\": [\n        {\n            \"Name\": \"GAS\",\n            \"Type\": \"Runtime\",\n            \"LoadingPhase\": \"Default\",\n            \"AdditionalDependencies\": [\n                \"Engine\"\n            ]\n        }\n    ],\n    \"Plugins\": [\n        {\n            \"Name\": \"GameplayAbilities\",\n            \"Enabled\": true\n        }\n    ]\n}\n",[41,1081,1079],{"__ignoreMap":39},[11,1083,1084],{},"重新编译，这样一来终于能够运行了。",[11,1086,1087],{},"不过Module的加载错误因项目而异，遇到这种错误还是必须使用GFlag进行调试才行。",[11,1089,1090],{},"最后，不要忘记在GFlag中把调试选项关掉，要不然调试运行速度会很感人的。",{"title":39,"searchDepth":53,"depth":59,"links":1092},[1093,1094,1095],{"id":891,"depth":53,"text":892},{"id":931,"depth":53,"text":932},{"id":1007,"depth":53,"text":1008},"2017-06-05",{"layout":535,"status":536,"published":104,"author":1098,"author_login":539,"author_email":540,"wordpress_id":1099,"wordpress_url":1100,"date_gmt":1101,"excerpt":1102},{"display_name":538,"login":539,"email":540,"url":39},1771,"\u002F\u002F?p=1771","2017-06-05 13:38:21 +0000",{"type":8,"value":1103},[1104],[11,1105,882],{},"\u002F2017-06-05-ue4-transition-log",{"title":877,"description":882},"_legacy\u002F2017\u002F2017-06-05-ue4-transition-log",[552],"0iGe3VdYh10THWts3bUSuhKTRSuDSFHgXdb-IH4CPnk",{"id":1112,"title":1113,"body":1114,"date":1326,"description":1118,"extension":533,"meta":1327,"navigation":104,"path":1336,"seo":1337,"stem":1338,"tags":1339,"__hash__":1342},"blogs\u002F_legacy\u002F2017\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note.md","UE4官方Multipass Rendering笔记",{"type":8,"value":1115,"toc":1314},[1116,1119,1128,1131,1134,1137,1140,1145,1148,1151,1157,1160,1166,1169,1172,1178,1181,1184,1190,1193,1198,1201,1204,1207,1211,1214,1220,1223,1227,1230,1236,1239,1244,1247,1250,1253,1258,1261,1264,1267,1270,1273,1279,1283,1286,1289,1292,1296,1299,1302,1306,1309,1311],[11,1117,1118],{},"这是一篇记录性笔记，可能并没有什么实质性的内容。",[11,1120,1121,1122,1127],{},"看这个视频本质上就是出于一个误会，视频标题是",[339,1123,1126],{"href":1124,"rel":1125},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=QGIKrD7uHu8",[665],"Content-Driven Mulipass Rendering","，并不是针对某个特效的Step-by-step的教程，而是一些原理上的解释。",[11,1129,1130],{},"故而其中有很多内容都是关于3D渲染的公式和实现的，因此也就不会进行深入的研究。之所以选择UE4这样的引擎来做游戏，就是为了避免过度的接触细节。就像是学习高级语言之后，编译原理什么的粗略了解就可以了。",[11,1132,1133],{},"当然，遇到了非实现不可的特效的时候也没有办法。说实话，不太想和那些Paper呀、公式呀什么的打交道：D",[23,1135,1136],{"id":1136},"材质原理",[11,1138,1139],{},"视频中提到的两个概念很有作用，就是Scatter和Gather",[11,1141,1142],{},[1042,1143],{"alt":1044,"src":1144},"\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image001_thumb.png",[11,1146,1147],{},"官方的RT示例中，水波纹扩散就是使用的Gather的方式进行运算的。",[11,1149,1150],{},"这是以前在理解上的一个误区，不能将整个运算目标当作一张贴图来看待，而应该去思考没一个区域（像素）应该处于什么状态。",[11,1152,1153],{},[1042,1154],{"alt":1155,"src":1156},"clip_image002","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image002_thumb.png",[11,1158,1159],{},"以及",[11,1161,1162],{},[1042,1163],{"alt":1164,"src":1165},"clip_image003","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image003_thumb.png",[23,1167,1168],{"id":1168},"透视光学",[11,1170,1171],{},"视频中有提到水面的折射近似算法，就是所谓的Experience Based Magic Method。",[11,1173,1174],{},[1042,1175],{"alt":1176,"src":1177},"clip_image004","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image004_thumb.png",[11,1179,1180],{},"在光学现象中，还有提到chromatic aberration，也就是色差的实现方式。",[11,1182,1183],{},"色差的基础实现使用RGB Offset，不过演示中使用了spectral photons来进行。但pectral photons究竟是什么却没有搞明白，粗略搜索了一下也不得其门而入。感觉上像是光谱聚合吧，使用光谱这样的线条来进行模拟而不是根据点来进行计算，可以减少运算量。",[11,1185,1186],{},[1042,1187],{"alt":1188,"src":1189},"clip_image005","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image005_thumb.png",[11,1191,1192],{},"另外，色差是什么呢？可以参照维基百科的解释：",[576,1194,1195],{},[11,1196,1197],{},"色差是指光学上透镜无法将各种波长的色光都聚焦在同一点上的现象。它的产生是因为透镜对不同波长的色光有不同的折射率（色散现象）。",[11,1199,1200],{},"对于水面的模拟很有作用，不过实际上，这部分的原理并不是特别的重要，社区有个Ocean的项目对水面、水下的效果模拟都处理的比较好。",[23,1202,1203],{"id":1203},"特效",[11,1205,1206],{},"在视频页面能够找到项目的下载地址，项目中就是在视频里面演示的那些效果。",[176,1208,1210],{"id":1209},"flowmappainter","FlowMapPainter",[11,1212,1213],{},"基于RenderTarget绘制的FlowMap水面演示",[11,1215,1216],{},[1042,1217],{"alt":1218,"src":1219},"clip_image006","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image006_thumb.png",[11,1221,1222],{},"总体和ContentExample里面的RenderTarget在原理上是差不多的，使用的FlowMap也是材质节点，如果有用到的话可以参考一下。",[176,1224,1226],{"id":1225},"fluidsimulation","FluidSimulation",[11,1228,1229],{},"流体模拟",[11,1231,1232],{},[1042,1233],{"alt":1234,"src":1235},"clip_image007","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image007_thumb.png",[11,1237,1238],{},"基于纳维－斯托克斯方程（Navier-Stokes equations）的流体模拟，这个方程可以参考下维基的解释：",[576,1240,1241],{},[11,1242,1243],{},"纳维－斯托克斯方程（Navier-Stokes equations），以克劳德-路易·纳维（Claude-Louis Navier）和乔治·斯托克斯命名，是一组描述像液体和空气这样的流体物质的方程。这些方程建立了流体的粒子动量的改变率（力）和作用在液体内部的压力的变化和耗散粘滞力（类似于摩擦力）以及重力之间的关系。这些粘滞力产生于分子的相互作用，能告诉我们液体有多粘。这样，纳维-斯托克斯方程描述作用于液体任意给定区域的力的动态平衡。",[11,1245,1246],{},"很复杂……",[11,1248,1249],{},"第一步，Advect，似乎是叫平流计算？不过日式的叫法移流方程式似乎更加的能方便理解，据说原理和上面的FlowMap的差不多。",[11,1251,1252],{},"第二步，计算散度，散度这个东西似乎以前物理中有学过。",[576,1254,1255],{},[11,1256,1257],{},"散度是向量分析中的一个向量算子，将向量空间上的一个向量场（矢量场）对应到一个标量场上。散度描述的是向量场里一个点是汇聚点还是发源点，形象地说，就是这包含这一点的一个微小体元中的向量是“向外”居多还是“向内”居多。举例来说，考虑空间中的静电场，其空间里的电场强度是一个矢量场。正电荷附近，电场线“向外”发射，所以正电荷处的散度为正值，电荷越大，散度越大。负电荷附近，电场线“向内”，所以负电荷处的散度为负值，电荷越大，散度越小。",[11,1259,1260],{},"就是这样的一个感觉。",[11,1262,1263],{},"第三步，计算压力；第四步，计算压力梯度。",[11,1265,1266],{},"这两步都是压力处理，在视频中讲解时似乎被算做了一步：D",[11,1268,1269],{},"每一步都会使用到部分前面计算的结果，全部都是通过RenderTarget进行中继的。",[11,1271,1272],{},"项目中有几个示例，分别是2D空间和3D空间内的流体模拟。",[11,1274,1275],{},[1042,1276],{"alt":1277,"src":1278},"clip_image008","\u002Fwp-content\u002Fuploads\u002F2017\u002F06\u002Fclip_image008_thumb.png",[176,1280,1282],{"id":1281},"hitmaskrender","HitMaskRender",[11,1284,1285],{},"就是在被命中的地方展示受到伤害的贴图，由于有密集恐惧症，就不贴图了，原理上比上面的都简单，就只是利用RenderTarget来做一个Mask而已。",[11,1287,1288],{},"但是其材质蓝图也是很复杂的，官方这个展示在各个细节方面都很\"认真\"。不仅仅做了mask，还有做法线上的Mask处理。",[11,1290,1291],{},"不过不知为何有几个地方有莫名的蓝图失连……所以怎么也没法把项目还原到官方视频中的那个效果。还有一个地方就是可能因为视频制作的时间比较靠前，在获取目标点的UV时，没有使用后面有的Trace UV功能，而是制作了一个UnWrap的Material来操作。",[176,1293,1295],{"id":1294},"paintingvoluemtextures","PaintingVoluemTextures",[11,1297,1298],{},"非常酷炫的使用VR进行绘制的云的效果，是VR的……没法测试。",[11,1300,1301],{},"原理上和流体的应该差不多。",[176,1303,1305],{"id":1304},"volumetextures","VolumeTextures",[11,1307,1308],{},"就是官方展示的那个3D的UV动画效果，使用了Custom Node，然后里面是有些复杂的Shader……",[23,1310,836],{"id":836},[11,1312,1313],{},"果然做特效是件很复杂是事情，3D图形学实在可怕，还好引擎已经将大部分东西都封装好了，只要不追求酷炫，基本就不太需要关心这些，大概……",{"title":39,"searchDepth":53,"depth":59,"links":1315},[1316,1317,1318,1325],{"id":1136,"depth":53,"text":1136},{"id":1168,"depth":53,"text":1168},{"id":1203,"depth":53,"text":1203,"children":1319},[1320,1321,1322,1323,1324],{"id":1209,"depth":59,"text":1210},{"id":1225,"depth":59,"text":1226},{"id":1281,"depth":59,"text":1282},{"id":1294,"depth":59,"text":1295},{"id":1304,"depth":59,"text":1305},{"id":836,"depth":53,"text":836},"2017-06-03",{"layout":535,"status":536,"published":104,"author":1328,"author_login":539,"author_email":540,"wordpress_id":1329,"wordpress_url":1330,"date_gmt":1331,"excerpt":1332},{"display_name":538,"login":539,"email":540,"url":39},1765,"\u002F\u002F?p=1765","2017-06-03 08:26:07 +0000",{"type":8,"value":1333},[1334],[11,1335,1118],{},"\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note",{"title":1113,"description":1118},"_legacy\u002F2017\u002F2017-06-03-ue4-content-driven-mulipass-rendering-note",[552,1340,1341],"RenderTarget","Rendering","NJsTELXWuLwdbFnOd8Ez1DGEBE4ywsugN5G3tLrwTSg",{"id":1344,"title":1345,"body":1346,"date":1555,"description":1350,"extension":533,"meta":1556,"navigation":104,"path":1565,"seo":1566,"stem":1567,"tags":1568,"__hash__":1570},"blogs\u002F_legacy\u002F2017\u002F2017-05-21-ue4-new-animation-and-physics.md","UE4.16新动画与物理功能",{"type":8,"value":1347,"toc":1548},[1348,1351,1360,1364,1367,1370,1373,1379,1382,1387,1390,1395,1398,1401,1406,1409,1415,1418,1421,1425,1428,1433,1436,1441,1444,1448,1451,1454,1459,1462,1467,1470,1474,1477,1480,1485,1488,1493,1496,1501,1504,1509,1512,1517,1520,1525,1528,1533,1536,1539,1542,1545],[11,1349,1350],{},"4.16的Preview更新已经发布有一段时间了，与以往一样，这次的版本更新也带来了很多新的功能与改变。",[11,1352,1353,1354,1359],{},"本文主要参照官方的功能[",[339,1355,1358],{"href":1356,"rel":1357},"https:\u002F\u002Fwww.slideshare.net\u002FEpicGamesJapan\u002Funreal-engine-75203047",[665],"演示文稿","]进行整理完成。",[23,1361,1363],{"id":1362},"基于rig的动画编辑","基于Rig的动画编辑",[11,1365,1366],{},"Rig是一种很方便的驱动骨骼动画的方式，本次的更新中添加了新的Rig动画编辑功能。",[11,1368,1369],{},"这个功能使得在编辑器中对Rig动画进行编辑变得可能，让我们进行更方便对动画调整和原型设计。",[11,1371,1372],{},"要想开启Rig动画编辑功能，首先要开启Control Rig插件：",[11,1374,1375],{},[1042,1376],{"alt":1377,"src":1378},"image","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-14.png",[11,1380,1381],{},"启用插件之后就可以在编辑器中看到这个模块到功能了：",[11,1383,1384],{},[1042,1385],{"alt":1377,"src":1386},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-15.png",[11,1388,1389],{},"中这个选项卡中新建一个Rig Sequence，然后拖一个骨骼Mesh进来当作目标，就可以在Sequence到编辑器中进行动画到编辑了：",[11,1391,1392],{},[1042,1393],{"alt":1377,"src":1394},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-16.png",[11,1396,1397],{},"编辑过程比较直观，也可以在IK与FK模式中进行切换，完成的动画可以导出成动画序列，在这个编辑器中也可以进行Retarget操作。",[11,1399,1400],{},"要导出动画，在Content Manager中找到Control Rig Sequence并点击右键，就可以看到相关到选项",[11,1402,1403],{},[1042,1404],{"alt":1377,"src":1405},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-17.png",[11,1407,1408],{},"然后就可以进行选择设置了",[11,1410,1411],{},[1042,1412],{"alt":1413,"src":1414},"SNAGHTML6685395","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002FSNAGHTML6685395_thumb.png",[11,1416,1417],{},"但是似乎没有看到从动画序列转换到Rig Sequence到方法。",[11,1419,1420],{},"Rig相关功能在4.16之后似乎还会增强，使得动画蓝图可以对Rig进行控制以及生成。",[23,1422,1424],{"id":1423},"live-link","Live Link",[11,1426,1427],{},"很强大的功能，使得UE4与其他的3D编辑器可以实时的联动编辑。这样就能更加直观的看到需要做的内容做UE4中是如何工作的。",[11,1429,1430],{},[1042,1431],{"alt":1377,"src":1432},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-18.png",[11,1434,1435],{},"看起来非常的实用",[11,1437,1438],{},[1042,1439],{"alt":1377,"src":1440},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-19.png",[11,1442,1443],{},"不过这个似乎要到4.17才会进入试验阶段……",[23,1445,1447],{"id":1446},"immediate-mode","Immediate Mode",[11,1449,1450],{},"之前的Physx是使用所谓保留模式（Retained Mode）工作的，Retained Mode有不少优点，方便实用。但是也有很多缺点，例如中对物体对Deactive逻辑处理时有不少效率上的问题、对物体进行遍历并不方便、很难对特定对物体组进行模拟成本计算等。",[11,1452,1453],{},"而Immediate Mode通过暴露出更多等底层操作接口，使得引擎能够更有效的对物理引擎进行控制和契合，同时也能大幅度的提升LOD以及Culing机制下的物理效率。",[11,1455,1456],{},[1042,1457],{"alt":1377,"src":1458},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-20.png",[11,1460,1461],{},"这个功能目前的一个主要应用是运动角色模型上的小的物体，这是一个在动画蓝图中的新节点：",[11,1463,1464],{},[1042,1465],{"alt":1377,"src":1466},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-21.png",[11,1468,1469],{},"它使得在动画蓝图中进行物理资源的模拟变得可能，这种方式比AnimDynamic的方式更方便进行操作，也具有更高的效率。",[23,1471,1473],{"id":1472},"nvcloth","NvCloth",[11,1475,1476],{},"4.16开始UE4中开始使用NVIDIA的新的Cloth框架：NvCloth，它能直接在引擎中进行材质制作，大大的减少了以前必须使用Apex外部制作工具带来的很多麻烦。",[11,1478,1479],{},"同时NvCloth也获得了Immediate Mode的优势，使得Cloth的仿真效能得到增强。NvCloth也应用了新的空气阻力模型",[11,1481,1482],{},[1042,1483],{"alt":1377,"src":1484},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-22.png",[11,1486,1487],{},"要使用NvCloth首先需要中试验性功能中打开这个功能：",[11,1489,1490],{},[1042,1491],{"alt":1377,"src":1492},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-23.png",[11,1494,1495],{},"然后就可以在骨骼Mesh的编辑器中选中区域选择：",[11,1497,1498],{},[1042,1499],{"alt":1377,"src":1500},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-24.png",[11,1502,1503],{},"这之后选择相应的区域就可以对其进行Cloth绘制了：",[11,1505,1506],{},[1042,1507],{"alt":1377,"src":1508},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-25.png",[11,1510,1511],{},"添加后就能看到新的区域了",[11,1513,1514],{},[1042,1515],{"alt":1377,"src":1516},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-26.png",[11,1518,1519],{},"不过这里暂时没什么用，最主要的还是绘制的过程：",[11,1521,1522],{},[1042,1523],{"alt":1377,"src":1524},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-27.png",[11,1526,1527],{},"在窗口中能看到ClothPaint，打开之后进行权重绘制即可。",[11,1529,1530],{},[1042,1531],{"alt":1377,"src":1532},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-28.png",[11,1534,1535],{},"因为手头没有模型，无法进行绘制测试，看官方的演示的话，NvCloth无论是从效果上还是效率上都比原来的Apex路径强很多。",[23,1537,1538],{"id":1538},"其他",[11,1540,1541],{},"在最近的引擎更新中有很多Robo Recall相关的功能实现被合并到了引擎中。",[11,1543,1544],{},"其中前向渲染的添加、运动物体上的CCD、pose snapshot、Constraint profile以及用于模拟移动有一定重量物体的Spring Lerp等已经在之前的版本中添加到了引擎中。",[11,1546,1547],{},"另外似乎有新的粒子系统在制作中，很期待接下来的版本更新。",{"title":39,"searchDepth":53,"depth":59,"links":1549},[1550,1551,1552,1553,1554],{"id":1362,"depth":53,"text":1363},{"id":1423,"depth":53,"text":1424},{"id":1446,"depth":53,"text":1447},{"id":1472,"depth":53,"text":1473},{"id":1538,"depth":53,"text":1538},"2017-05-21",{"layout":535,"status":536,"published":104,"author":1557,"author_login":539,"author_email":540,"wordpress_id":1558,"wordpress_url":1559,"date_gmt":1560,"excerpt":1561},{"display_name":538,"login":539,"email":540,"url":39},1738,"\u002F\u002F?p=1738","2017-05-21 15:51:45 +0000",{"type":8,"value":1562},[1563],[11,1564,1350],{},"\u002F2017-05-21-ue4-new-animation-and-physics",{"title":1345,"description":1350},"_legacy\u002F2017\u002F2017-05-21-ue4-new-animation-and-physics",[552,1472,1569],"Animation","hEJJu0weqtXDxRLWNMRQ6X90OGRMe63j2oph88zyr_s",85,1788763178312]