[{"data":1,"prerenderedAt":228},["ShallowReactive",2],{"\u002F2021-01-24-ue4-level-editor-notes":3},{"id":4,"title":5,"body":6,"date":205,"description":12,"extension":206,"meta":207,"navigation":210,"path":222,"seo":223,"stem":224,"tags":225,"__hash__":227},"blogs\u002F_legacy\u002F2021\u002F2021-01-24-ue4-level-editor-notes.md","UE4关卡编辑问题记录",{"type":7,"value":8,"toc":191},"minimark",[9,13,16,21,24,27,30,41,44,50,53,57,63,66,72,75,81,84,90,93,96,103,106,109,112,116,119,122,125,128,131,144,148,151,154,158,161,167,170,176,179,185,188],[10,11,12],"p",{},"最近自己摆弄关卡遇到的一些问题的记录。",[10,14,15],{},"由于近段时间基本一直在作逻辑开发，所以很少自己碰编辑器，发现一些常见的问题也不知道该如何应对。于是统一的记录了起来，方便下次查找原因。",[17,18,20],"h2",{"id":19},"texture-streaming-over-budget","Texture streaming over budget",[10,22,23],{},"结论写在前面，基本原因是默认配置太小，调大就可以了。",[10,25,26],{},"主要是直接输出一个红色的错误日志在顶部，让人担心自己是不是做错了什么。",[10,28,29],{},"首先，找到日志输出的地方：",[31,32,37],"pre",{"className":33,"code":35,"language":36},[34],"language-text","SmallTextItem.SetColor(FLinearColor::Red); \nSmallTextItem.Text = FText::Format(LOCTEXT(\"TEXTURE_STREAMING_POOL_OVER_BUDGET_FMT\", \"TEXTURE STREAMING POOL OVER {0} BUDGET\"), FText::AsMemory(MemOver)); \nCanvas->DrawItem(SmallTextItem, FVector2D(MessageX, MessageY));\n","text",[38,39,35],"code",{"__ignoreMap":40},"",[10,42,43],{},"这个东西的计算在：",[31,45,48],{"className":46,"code":47,"language":36},[34],"FRenderAssetStreamingMipCalcTask::UpdateStats_Async\n",[38,49,47],{"__ignoreMap":40},[10,51,52],{},"中，主要有两个来源：",[54,55,56],"h3",{"id":56},"内存池超过限制",[31,58,61],{"className":59,"code":60,"language":36},[34],"Stats.OverBudget += FMath::Max\u003Cint64>(Stats.RequiredPool - Stats.StreamingPool, 0);\n",[38,62,60],{"__ignoreMap":40},[10,64,65],{},"用实际消耗的内存大小减去MemoryBudget，RequairedPool就是每一个FStreamingRenderAsset的消耗加起来",[31,67,70],{"className":68,"code":69,"language":36},[34],"Stats.RequiredPool += RequiredSize;\n",[38,71,69],{"__ignoreMap":40},[54,73,74],{"id":74},"单个物体超过限制",[31,76,79],{"className":77,"code":78,"language":36},[34],"\u002F\u002F All persistent mip bias bigger than the expected is considered overbudget. \nconst int32 OverBudgetBias = FMath::Max\u003Cint32>(0, StreamingRenderAsset.BudgetMipBias - Settings.GlobalMipBias); \nStats.OverBudget += StreamingRenderAsset.GetSize(StreamingRenderAsset.MaxAllowedMips + OverBudgetBias) - MaxSize;\n",[38,80,78],{"__ignoreMap":40},[10,82,83],{},"这里累计进去的就是OverBudgetBias，因为前面",[31,85,88],{"className":86,"code":87,"language":36},[34],"const int64 MaxSize = StreamingRenderAsset.GetSize(StreamingRenderAsset.MaxAllowedMips);\n",[38,89,87],{"__ignoreMap":40},[54,91,92],{"id":92},"实际分析",[10,94,95],{},"这样的话，直接stat streaming，看结果",[10,97,98],{},[99,100],"img",{"alt":101,"src":102},"image-20201227191346947","\u002Fwp-content\u002Fuploads\u002F2021\u002F01\u002Fimage-20201227191346947_thumb.png",[10,104,105],{},"这里就是配置太小了，不知为什么默认只有76M，这样随便上几个大点的pbr贴图就超过了。通过指令上调配置就好。",[10,107,108],{},"r.Streaming.PoolSize 2000",[10,110,111],{},"也就是说，实际上是默认配置太小导致的，不是哪里操作有问题。",[17,113,115],{"id":114},"instancemesh","InstanceMesh",[10,117,118],{},"目前共有UInstancedStaticMeshComponent和UHierarchicalInstancedStaticMeshComponent两个组件，但是他们有什么区别呢？一旦开始纠结就不知道应该选哪一个了。",[10,120,121],{},"稍微查了下资料，主要的区别是。UHierarchicalInstancedStaticMeshComponent是会按instance更新LOD的，而UInstancedStaticMeshComponent则全部统一使用同一个LOD。",[54,123,124],{"id":124},"本身的限制",[10,126,127],{},"由于目前的版本会自动合批，不是很确定UInstancedStaticMeshComponent还有没有必要性。不过至少会减少Actor的数量，也方便使用Cluster来减少GC负担。",[10,129,130],{},"InstanceMesh的限制：",[132,133,134,138,141],"ol",{},[135,136,137],"li",{},"无法使用负数的Scale",[135,139,140],{},"无法分别指定材质(per instance random可用于一些效果)",[135,142,143],{},"碰撞不会在运行时更新(这个现在应该没有了)",[54,145,147],{"id":146},"crash","Crash",[10,149,150],{},"实际使用instancemesh，发现在编辑器里面直接ctrl+w会崩溃，主要原因是instance的生成直接放到构造函数里面了。",[10,152,153],{},"正确的做法是，将生成放到OnConstruction里面，还能在改变属性时自动更新。",[17,155,157],{"id":156},"bound","Bound",[10,159,160],{},"在愉快的拖动关卡的时候，突然出现了这样的报错：",[162,163,164],"blockquote",{},[10,165,166],{},"The actor will be placed outside the bounds of the current level. Continue?",[10,168,169],{},"于是找了下输出来源，这个Bound似乎是实时计算的",[31,171,174],{"className":172,"code":173,"language":36},[34],"FBox CurrentLevelBounds(ForceInit);\nif (InLevel-&gt;LevelBoundsActor.IsValid())\n{\n    CurrentLevelBounds = InLevel-&gt;LevelBoundsActor.Get()-&gt;GetComponentsBoundingBox();\n}\nelse\n{\n    CurrentLevelBounds = ALevelBounds::CalculateLevelBounds(InLevel);\n}\n",[38,175,173],{"__ignoreMap":40},[10,177,178],{},"在有LevelBoundsActor的情况下，会使用指定的Bound",[31,180,183],{"className":181,"code":182,"language":36},[34],"\u002F**\n *\n * Defines level bounds\n * Updates bounding box automatically based on actors transformation changes or holds fixed user defined bounding box\n * Uses only actors where AActor::IsLevelBoundsRelevant() == true\n *\u002F\n",[38,184,182],{"__ignoreMap":40},[10,186,187],{},"也就是说，没有自己指定边界Actor为自定义的话，其实没什么太大的意义。",[10,189,190],{},"可以在编辑器设置中关闭bPromptWhenAddingToLevelOutsideBounds。",{"title":40,"searchDepth":192,"depth":193,"links":194},2,3,[195,200,204],{"id":19,"depth":192,"text":20,"children":196},[197,198,199],{"id":56,"depth":193,"text":56},{"id":74,"depth":193,"text":74},{"id":92,"depth":193,"text":92},{"id":114,"depth":192,"text":115,"children":201},[202,203],{"id":124,"depth":193,"text":124},{"id":146,"depth":193,"text":147},{"id":156,"depth":192,"text":157},"2021-01-24","md",{"layout":208,"status":209,"published":210,"author":211,"author_login":213,"author_email":214,"wordpress_id":215,"wordpress_url":216,"date_gmt":217,"excerpt":218},"post","publish",true,{"display_name":212,"login":213,"email":214,"url":40},"风铃","flinkor","flinkor@foxmail.com",3226,"\u002F?p=3226","2021-01-24 03:19:43 +0000",{"type":7,"value":219},[220],[10,221,12],{},"\u002F2021-01-24-ue4-level-editor-notes",{"title":5,"description":12},"_legacy\u002F2021\u002F2021-01-24-ue4-level-editor-notes",[226],"UE4","aC2fbb4Y1BSs1AdibFkWM6TlG677lO2kh_AymzB3kJo",1788763177366]