[{"data":1,"prerenderedAt":1291},["ShallowReactive",2],{"page-物理-1":3,"page-count-物理":1206},[4,192,439,812,1085],{"id":5,"title":6,"body":7,"date":167,"description":13,"extension":168,"meta":169,"navigation":172,"path":184,"seo":185,"stem":186,"tags":187,"__hash__":191},"blogs\u002F_legacy\u002F2018\u002F2018-01-01-ue4-project-notes.md","UE4项目笔记汇总",{"type":8,"value":9,"toc":154},"minimark",[10,14,17,21,24,27,31,34,43,46,49,53,56,59,62,65,68,71,74,85,88,91,94,97,100,106,109,113,116,120,123,126,132,135,139,142,145,151],[11,12,13],"p",{},"这里是过去一段与项目有关的笔记汇总，把一些零零碎碎的给合在了一起。",[11,15,16],{},"由于项目一直停留在4.15，所以本文所有内容都是基于UE4.15.3的。",[18,19,20],"h2",{"id":20},"物理相关",[11,22,23],{},"由于做的项目对运动的精度要求比较高，所以和物理打了很长一段时间的交道。",[11,25,26],{},"在用UE4之前基本没接触过3D的物理引擎。好在之前有用过Box2D，一些基本的物理引擎原理还是有些了解的。",[28,29,30],"h3",{"id":30},"球体运动",[11,32,33],{},"遇到的第一个问题是球体运动相关的，Physx对球体运动的模拟有些糟糕。",[11,35,36,37,42],{},"主要表现是Friction对球体的速度影响相当的微妙，导致球的运动很难停下来。而如果使用LinearDumping和AngularDumping来进行速度制御的话，由于其并不是匀减速的，而且即便与Friction没有关系，运动也不真实。这部分的解决方案之前已经记录在[",[38,39,41],"a",{"href":40},"\u002F2017-05-03-ue4-physx-and-substepping\u002F","UE4中的Physx物理","]这篇文章中了，总之就是自己接管物理的部分运算。",[11,44,45],{},"更加区域的注册自己添加上摩擦力和反弹。途中遇到过很多问题，现在回头看的话，发现代码的实现还是不够简洁。",[11,47,48],{},"而且虽然一开始坚持想要存依靠公式来进行运动控制，但最后还是往里面添加了不少“黑魔法”……",[28,50,52],{"id":51},"foliage碰撞","Foliage碰撞",[11,54,55],{},"后面出现的一个需求是关于Foliage的碰撞的，总体而言就是需要树的不同部分表现出不同的碰撞特性。",[11,57,58],{},"比如树叶区域进行Overlap，而树干区域进行Block。但是由于Foliage本身是一种Instanced的Actor，UE4在实现时，对于同一个FoliageType只能使用一个碰撞配置。",[11,60,61],{},"不过Instance主要是针对渲染而进行的一种优化方案，既然Foliage是可以进行碰撞的，那么在Physx world中肯定是有注册碰撞形态的。",[11,63,64],{},"几经探索之后终于找到解决方案，通过UE4提供的Physx底层Api，将Foliage Type实例化之后的碰撞形态取出，单独将Capsule的碰撞形态重新注册到Physx中去。",[11,66,67],{},"这里本来是想直接对PxActor的碰撞配置进行修改的，但是UE4在上层有封装，无法将Overlap的物体的碰撞响应传递出去。所以只有采取取出重新注册的方案。",[11,69,70],{},"但是由于场景中的Foliage实在是太多，在地图载入时进行整体性操作会导致不可接受的时间消耗，最后采用动态转化的方案，将玩家周围的Foliage取出，并拉取出Capsule来实现。",[11,72,73],{},"这里面有遇到一个困扰了很久的问题，那就是Capsule取出之后怎么都无法找到正确的对应Roation。几经周折才发现UE4中的Capsule和Physx中的Capsule是有不同的默认朝向的，需要手动进行一次转化才行：",[75,76,81],"pre",{"className":77,"code":79,"language":80},[78],"language-text","static const PxQuat CapsuleRotator(0.f, 0.707106781f, 0.f, 0.707106781f);\n\nPxQuat ConvertToPhysXCapsuleRot(const FQuat& GeomRot)\n{\n  \u002F\u002F Rotation required because PhysX capsule points down X, we want it down Z\n  return U2PQuat(GeomRot) * CapsuleRotator;\n}\n\nFQuat ConvertToUECapsuleRot(const PxQuat & PGeomRot)\n{\n return P2UQuat(PGeomRot * CapsuleRotator.getConjugate());\n}\n","text",[82,83,79],"code",{"__ignoreMap":84},"",[18,86,87],{"id":87},"屏幕偏移",[11,89,90],{},"就是要让FOV的计算有一个Offset，当时查了很多资料。只在AnswerHub找到一个旧版本的不是很完全的实现。",[11,92,93],{},"好在通过那个页面里的讨论找到了解决的方向，而不用自己深入到UE4的渲染代码中去找Hack Point。",[11,95,96],{},"最主要的问题是，讨论最后给出的Viewport的转换矩阵是错的，转换之后的结果并不能让人满意。UE4的渲染实现并不“标准”，所以使用通用的摄像投影矩阵还是无法实现类似视点中心偏移的效果。",[11,98,99],{},"最后终于在代码深处的BlendCamera中找到了UE4本身对视角偏移的处理，得出了“正确”的偏移矩阵",[75,101,104],{"className":102,"code":103,"language":80},[78],"\u002F** 计算投影矩阵 *\u002F\nfloat t_fRatio = InCamera->AspectRatio;\nif (!InCamera->bConstrainAspectRatio)\n{\n t_fRatio = t_ScreenSize.X \u002F t_ScreenSize.Y;\n}\n\nfloat t_fFov = InCamera->FieldOfView;\nfloat t_fNear = GNearClippingPlane;\n\nresult = FReversedZPerspectiveMatrix(t_fFov * PI \u002F 360.0f, t_fRatio, 1.0f, t_fNear);\n\nif (Offset.IsZero())\n{\n return true;\n}\n\n\u002F** 将Offset规范到百分比 *\u002F\nOffset.X \u002F= (t_ScreenSize.X \u002F 2.0f);\nOffset.Y \u002F= (t_ScreenSize.Y \u002F 2.0f);\n\n\u002F** Clamp以避免“过度”偏移 *\u002F\nOffset = FMath::Clamp(Offset, FVector2D(-1, -1), FVector2D(1, 1));\n\nconst float Left = -1.0f + Offset.X;\nconst float Right = Left + 2.0f;\nconst float Bottom = -1.0f + Offset.Y;\nconst float Top = Bottom + 2.0f;\n\nresult.M[2][0] = (Left + Right) \u002F (Left - Right);\nresult.M[2][1] = (Bottom + Top) \u002F (Bottom - Top);\n",[82,105,103],{"__ignoreMap":84},[11,107,108],{},"不过，当时由于实现的比较急切，直接沿用讨论的方向，对Viewport类进行了重载，也使用了一些“黑魔法，虽然至今没有观测到副作用，但是现在想来，其实还是有其他的解决方案的。",[18,110,112],{"id":111},"ui相关","UI相关",[11,114,115],{},"UMG只实现了默认的几种常见的Widget，所以有很多需要实现的自定义控件。这个也算是UI开发的常态了，但是当时有两个问题还是困扰了一段时间。",[28,117,119],{"id":118},"slate的序列帧","Slate的序列帧",[11,121,122],{},"UMG的序列帧实现在社区可以找到，但是当需要在LoadingScreen上播放序列帧时就会有麻烦。因为那个时候UMG系统还没有初始化完成，只能使用Slate。",[11,124,125],{},"在参考了UE4的进度条实现之后，找到了相关的接口：",[75,127,130],{"className":128,"code":129,"language":80},[78],"FVector2D Min(FrameSize.X * Column, FrameSize.Y * Row);\nFVector2D Max = Min + FrameSize;\nFBox2D UVCoordinates(Min \u002F TextureSize, Max \u002F TextureSize);\nUVCoordinates.bIsValid = true;\n\nBrush.SetUVRegion(MoveTemp(UVCoordinates));\n",[82,131,129],{"__ignoreMap":84},[11,133,134],{},"这样就可以实现序列帧的切换了。",[28,136,138],{"id":137},"_2d画线","2D画线",[11,140,141],{},"FSlateDrawElement::MakeLines有一个问题，那就是不知为何最后实现的时候Thickness这个参数是不起作用的。",[11,143,144],{},"因此要画粗线就必须自己想办法，虽然试过很多方法，包括参考UE4内部的线段AA实现，但是最后还是采用了最不优雅的解决方案：多画几次。",[75,146,149],{"className":147,"code":148,"language":80},[78],"FVector2D DrawPosition;\nfor (; aTimes > 0; --aTimes)\n{\n DrawPosition = FVector2D::ZeroVector;\n if (m_bIsVert) DrawPosition.Y = aTimes;\n else DrawPosition.X = aTimes;\n\n FSlateDrawElement::MakeLines(\n  InContext.OutDrawElements,\n  InContext.MaxLayer,\n  InContext.AllottedGeometry.ToPaintGeometry(DrawPosition, FVector2D(1.0f,1.0f), 1.0f),\n  tLine,\n  InContext.MyClippingRect,\n  ESlateDrawEffect::None,\n  color,\n  true,\n  0.1f);\n}\n",[82,150,148],{"__ignoreMap":84},[11,152,153],{},"因为这样画出来的才是最平滑的，好在对粗细的要求并不高，否则可能会加大绘制的负担。",{"title":84,"searchDepth":155,"depth":156,"links":157},2,3,[158,162,163],{"id":20,"depth":155,"text":20,"children":159},[160,161],{"id":30,"depth":156,"text":30},{"id":51,"depth":156,"text":52},{"id":87,"depth":155,"text":87},{"id":111,"depth":155,"text":112,"children":164},[165,166],{"id":118,"depth":156,"text":119},{"id":137,"depth":156,"text":138},"2018-01-01","md",{"layout":170,"status":171,"published":172,"author":173,"author_login":175,"author_email":176,"wordpress_id":177,"wordpress_url":178,"date_gmt":179,"excerpt":180},"post","publish",true,{"display_name":174,"login":175,"email":176,"url":84},"风铃","flinkor","flinkor@foxmail.com",2170,"\u002F\u002F?p=2170","2017-12-31 16:01:50 +0000",{"type":8,"value":181},[182],[11,183,13],{},"\u002F2018-01-01-ue4-project-notes",{"title":6,"description":13},"_legacy\u002F2018\u002F2018-01-01-ue4-project-notes",[188,189,190],"UE4","UMG","物理","8GIMwwB_ylWoPujHfm3zYlq3ZQOiZ_ohYp777ox0kVk",{"id":193,"title":41,"body":194,"date":423,"description":198,"extension":168,"meta":424,"navigation":172,"path":433,"seo":434,"stem":435,"tags":436,"__hash__":438},"blogs\u002F_legacy\u002F2017\u002F2017-05-03-ue4-physx-and-substepping.md",{"type":8,"value":195,"toc":416},[196,199,202,205,209,212,215,221,224,231,234,237,240,245,248,252,255,258,263,266,269,274,277,281,284,290,293,299,302,310,316,319,325,328,334,337,345,348,351,357,360,366,369,373,376,379,382,385,391,401,404,407],[11,197,198],{},"为了保证物理引擎能够更精准的模拟，UE4有提供Physics Sub-Stepping功能，同时引擎也有提供相应的接口方便自行进行物理操作。",[11,200,201],{},"当前UE4版本4.16 P1。",[11,203,204],{},"UE4中对物理引擎的接口暴露还是相当多的，只是一般情况下不会使用到而已。",[18,206,208],{"id":207},"sub-stepping","Sub-Stepping",[11,210,211],{},"UE4的物理分步是所谓的半锁定步长形式的，无论如何分步的主要作用是提高物理模拟的精确度。针对的情况是，在不同的设备上，发布的程序可能会以不同的帧率运行。在有的设备上有可能会被进行奇怪的垂直同步设定，这些都有可能导致与帧率同步的物理模拟出现神奇的处理结果。",[11,213,214],{},"物理分步功能目前还不是特别完善，在代码中能看到注释：",[216,217,218],"blockquote",{},[11,219,220],{},"This feature is still experimental. Certain functionality might not work correctly",[11,222,223],{},"Sub-Stepping的设置在项目设置>Engine>Physics中。",[11,225,226],{},[227,228],"img",{"alt":229,"src":230},"image","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-2.png",[11,232,233],{},"在默认的情况下，不启用分布，作用于物理引擎的设定是Max Physics Delta Time。当前值是0.033333，也就是说物理引擎本身的运行不小于每秒30帧。",[11,235,236],{},"当启用了物理分步之后，引擎将会在每一帧中进行分步计算，当帧率下降到一帧时间大于最大分步数*最大分步时间的情况下，引擎将不再进行分步计算而是等待。无论如何，过小的物理分步将会导致更高的运算负荷，而且从某种程度上也并不是必要的。",[11,238,239],{},"引擎中有的与物理有关的代码中有提供bAllowSubstepping这样的选项来进行区分，当调用这些函数的来源是物理分步发出的事件时才需要将其置为FALSE。",[11,241,242],{},[227,243],{"alt":229,"src":244},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-3.png",[11,246,247],{},"物理分步还有三个扩展的属性，这些属性是分步时进行分步之间进行加权的平滑处理的。",[18,249,251],{"id":250},"async-scene","Async Scene",[11,253,254],{},"分步选项中还有一个Stepping Async的开关，这个选项是作用于Async Scene的，就是说是否对Async Scene进行分步计算。",[11,256,257],{},"但是Async Scene本身是需要另外开启的",[11,259,260],{},[227,261],{"alt":229,"src":262},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-4.png",[11,264,265],{},"在Physx中，有区分Synchronous与Asynchronous两种模式，而UE4中对其都有支持。Synchronous scene是通常的物理模拟发生的地方。而Asynchronous中存放的一般是可破坏物品等静态的、与游戏逻辑关联不大的物品。",[11,267,268],{},"静态的物品是同时存在于这两个Scene中的，而动态物品可以通过选项设定到Async Scene中。",[11,270,271],{},[227,272],{"alt":229,"src":273},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-5.png",[11,275,276],{},"但是静态物品会无视这个选项的，在碰撞中可以选择让物体在移动时也在Async Scene中检测碰撞。",[18,278,280],{"id":279},"custom-physics","Custom Physics",[11,282,283],{},"UE4中有提供介入物理引擎的方式，通过在bodyinstance或者PhysicsScene中定义的下面的函数进行事件绑定就好了：",[75,285,288],{"className":286,"code":287,"language":80},[78],"void AddCustomPhysics(FCalculateCustomPhysics& CalculateCustomPhysics);\n",[82,289,287],{"__ignoreMap":84},[11,291,292],{},"与基本的Event Dispatcher的实现一样，要使用这个功能首先要声明一个",[75,294,297],{"className":295,"code":296,"language":80},[78],"FCalculateCustomPhysics OnCalculateCustomPhysics;\n",[82,298,296],{"__ignoreMap":84},[11,300,301],{},"而与通常的事件不同的是，AddCustomPhysics必须在每次Tick时都进行绑定，这样它才会在接下来的物理执行中被调用。",[11,303,304,305,309],{},"通常的Tick的",[38,306,308],{"href":307},"\u002F2017-03-25-ue4-time-mange\u002F#TickGroup","TickGroup","都是在PrePhiscs中的，也就是说这个注册是针对每一个引擎Tick循环进行的。",[75,311,314],{"className":312,"code":313,"language":80},[78],"void UMyStaticMeshComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)\n{\n  Super::TickComponent(DeltaTime, TickType, ThisTickFunction);\n  GetBodyInstance()->AddCustomPhysics(OnCalculateCustomPhysics);\n}\n",[82,315,313],{"__ignoreMap":84},[11,317,318],{},"而自己要定义的事件则绑定到OnCalculateCustomPhysics中就行了",[75,320,323],{"className":321,"code":322,"language":80},[78],"OnCalculateCustomPhysics.BindUObject(this, &UMyStaticMeshComponent::MyCustomPhysx);\n",[82,324,322],{"__ignoreMap":84},[11,326,327],{},"分发器本身的定义是",[75,329,332],{"className":330,"code":331,"language":80},[78],"DECLARE_DELEGATE_TwoParams(FCalculateCustomPhysics, float, FBodyInstance*);\n",[82,333,331],{"__ignoreMap":84},[11,335,336],{},"在使用自定义物理时，需要注意，一些物理相关的类型是无法进行蓝图暴露的。如果强行暴露给蓝图，例如添加UCLASS之类的修饰的话，就会不经提醒出现这样的报错:",[216,338,339,342],{},[11,340,341],{},"Unrecognized type 'FCalculateCustomPhysics' - type must be a UCLASS, USTRUCT or UENUM",[11,343,344],{},"Inappropriate '*' on variable of type 'FBodyInstance', cannot have an exposed pointer to this type.",[11,346,347],{},"其实只要把蓝图暴露的修饰符去掉就可以了。",[11,349,350],{},"另外如果要直接调用Physx的API的话，就必需在项目的build.cs中添加\"PhysX\"和\"APEX\" 这两个Module的包含，类似下面这样就可以了",[75,352,355],{"className":353,"code":354,"language":80},[78],"PublicDependencyModuleNames.AddRange(new string[] { \"Core\", \"CoreUObject\", \"Engine\", \"InputCore\", \"PhysX\", \"APEX\" });\n",[82,356,354],{"__ignoreMap":84},[11,358,359],{},"这样的话就可以通过",[75,361,364],{"className":362,"code":363,"language":80},[78],"PRigidBody = GetBodyInstance()->GetPxRigidBody_AssumesLocked();\n",[82,365,363],{"__ignoreMap":84},[11,367,368],{},"来进行Physx的API调用了。",[18,370,372],{"id":371},"damping-and-force","Damping and Force",[11,374,375],{},"Physx对球体的运动模拟上有些许问题，通常的建议是对球体作用Linear Damping和Angular Damping让其运动停止。",[11,377,378],{},"但是如果在对物理真实度要求较高的情况下就会有一个问题，那就是Damping在速度较高时减速比速度较低时快，而在速度接近零时需要一定的时间才能够停住运动。当然，如果Damping很高的情况下也是会直接停的。",[11,380,381],{},"所以我们可以通过对RigidBody直接施加力量来达到减速的效果。",[11,383,384],{},"但是通常情况下最好不要直接对速度进行修改，而是通过AddForce之类的操作间接的对速度进行操作。因为物理引擎内部很多模拟计算是以“当前”速度为基准进行的，如果直接进行速度的设置，可能会导致一些计算的结果不太真实。而AddForce的话就可以将加速度等计算交由物理引擎自行处理。",[75,386,389],{"className":387,"code":388,"language":80},[78],"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",[82,390,388],{"__ignoreMap":84},[11,392,393,394,400],{},"这里需要注意的是，Physx与UE4的setLinearVelocity调用形式虽然是相同的，但第二个参数的意义是不同的。Physx的第二参数并不是Add to velocity而是auto wake。详细的addForce之类的可以参照[",[38,395,399],{"href":396,"rel":397},"http:\u002F\u002Fdocs.nvidia.com\u002Fgameworks\u002Fcontent\u002Fgameworkslibrary\u002Fphysx\u002Fapireference\u002Ffiles\u002FclassPxRigidBody.html",[398],"nofollow","Physx文档","]。",[11,402,403],{},"这样的话再添加上一些接触判定逻辑就可以实现自己的球体运动模拟了。",[18,405,406],{"id":406},"源码",[11,408,409,410,415],{},"一些更多的细节部分请参考[",[38,411,414],{"href":412,"rel":413},"https:\u002F\u002Fgithub.com\u002Fsteinkrausls\u002FPhysxTest",[398],"Github","]上的源码，里面只保留了测试代码，有些多余的代码没有完全去掉~",{"title":84,"searchDepth":155,"depth":156,"links":417},[418,419,420,421,422],{"id":207,"depth":155,"text":208},{"id":250,"depth":155,"text":251},{"id":279,"depth":155,"text":280},{"id":371,"depth":155,"text":372},{"id":406,"depth":155,"text":406},"2017-05-03",{"layout":170,"status":171,"published":172,"author":425,"author_login":175,"author_email":176,"wordpress_id":426,"wordpress_url":427,"date_gmt":428,"excerpt":429},{"display_name":174,"login":175,"email":176,"url":84},1659,"\u002F\u002F?p=1659","2017-05-03 15:15:23 +0000",{"type":8,"value":430},[431],[11,432,198],{},"\u002F2017-05-03-ue4-physx-and-substepping",{"title":41,"description":198},"_legacy\u002F2017\u002F2017-05-03-ue4-physx-and-substepping",[188,190,437],"Substeping","6Y9M-KkcwG2tKy8g5yLG0UdDxx2RabVFCSooiRT8HNI",{"id":440,"title":441,"body":442,"date":793,"description":446,"extension":168,"meta":794,"navigation":172,"path":806,"seo":807,"stem":808,"tags":809,"__hash__":811},"blogs\u002F_legacy\u002F2015\u002F2015-06-19-ue4%e7%89%a9%e4%bd%93%e7%a0%b4%e7%a2%8e.md","UE4物体破碎",{"type":8,"value":443,"toc":791},[444,447,450,453,458,463,471,484,487,490,496,502,505,510,513,518,521,526,529,534,537,542,545,548,553,556,561,564,569,572,577,582,585,590,593,598,601,606,609,614,617,622,625,630,633,638,641,646,649,654,657,662,665,670,675,678,683,686,691,694,699,702,707,710,715,718,723,728,731,736,739,744,747,752,755,758,767,770,775,782,785,788],[11,445,446],{},"UE4的破碎通过可破坏网格物体进行实现，任何一个网格都可以转换为可破坏的网格。",[11,448,449],{},"当前使用的UE4版本：4.8.0。",[11,451,452],{},"在实际使用中，要破坏一个物体就必须通过蓝图产生伤害或是在设置中设定碰撞伤害。传递伤害的蓝图节点如下：",[11,454,455],{},[227,456],{"alt":229,"src":457},"\u002Fwp-content\u002Fuploads\u002F2015\u002F06\u002Fimage_thumb2.png",[11,459,460],{},[227,461],{"alt":229,"src":462},"\u002Fwp-content\u002Fuploads\u002F2015\u002F06\u002Fimage_thumb3.png",[11,464,465,466,470],{},"破坏效果相关的设定几乎都可以在可破坏网格的属性页面进行调整。当前UE4版本中的碰撞面板只能产生深度为1的Voronoi破碎效果，一般情况下就足够使用了。如果需要复杂的破碎效果，例如敲破墙壁等，需要借助",[38,467,469],{"href":468},"\u002F?p=1168","Apex","来制作后导入引擎。破碎相关的属性中有几个概念比较重要。",[472,473,474,478,481],"ul",{},[475,476,477],"li",{},"支撑（Support）：一个可破碎的物体在实际的物理世界中是不会一受力就土崩瓦解的，那是因为物体与世界以及物体内部之间有支撑作用。支撑就是用来模拟这个效果的。",[475,479,480],{},"碎屑（Debris）：一些过小的碎片对于游戏模拟是没有意义的，可以让他们在一定条件下自行消失。",[475,482,483],{},"深度（Depth）：相当与破碎时的层级，当前UE4版本下需要使用Apex来生成。一般物体的部分破坏、复杂的支撑结构都需要借助多深度来实现。",[11,485,486],{},"可破坏物体的属性面板中影响比较大的是旗标设定，其余大部分属性都是Apex的属性，如果要使用Apex制作的话在这里需要重复设定的内容就比较少。",[11,488,489],{},"使用到的属性整理如下：",[11,491,492],{},[493,494,495],"em",{},"Flags",[11,497,498],{},[499,500,501],"strong",{},"Accumulate Damage",[11,503,504],{},"累积伤害，当打开时物体会累积所受到的伤害。当累积伤害超过阈值时就会破碎。",[11,506,507],{},[499,508,509],{},"Asset Defined Support",[11,511,512],{},"当打开时，标记为Is Support Chunk的块将会有支撑效果。",[11,514,515],{},[499,516,517],{},"World Support",[11,519,520],{},"当打开时，标记为Is Support Chunk的块与世界接触的部分将会获得支撑。",[11,522,523],{},[499,524,525],{},"Debris TimeOut",[11,527,528],{},"是否启用碎屑超时设定，当启用时碎屑将会在到达生命周期时被删除。",[11,530,531],{},[499,532,533],{},"Debris Max Separation",[11,535,536],{},"是否启用碎屑消亡距离设定，当启用时碎屑将会在到达消亡距离时被删除。",[11,538,539],{},[499,540,541],{},"Crumble Smallest Chunks",[11,543,544],{},"当开启时，系统会对最小的碎片进行瓦解。如果有设置对应的粒子系统则会使用粒子的效果，如果没有设置的话则直接清除该碎片。",[11,546,547],{},"另，目前蓝图中暂时没有找到指定瓦解粒子系统的设置点，灰尘粒子的指定也没有，暂时不会用到就没有做进一步的研究了。",[11,549,550],{},[499,551,552],{},"Accurate Raycasts",[11,554,555],{},"当开启时，将会使用射线追踪算法对所有与物体发生碰撞的碎片进行搜索。主要用于物体的实际形状和碰撞形态相差比较大的情况下，对破碎点和法线方向进行精确度修正。",[11,557,558],{},[499,559,560],{},"Use Valid Bounds",[11,562,563],{},"是否启用碎片的有效范围，当碎片超出这个范围时，将会被删除。",[11,565,566],{},[499,567,568],{},"Form Extended Structures",[11,570,571],{},"对于多个静态的可破坏物体，如果同时都有设置这个旗标的话。将会互相产生支撑作用。",[11,573,574],{},[493,575,576],{},"Damage",[11,578,579],{},[499,580,581],{},"Damage Threshold",[11,583,584],{},"伤害阈值，当受到的伤害大于这个数值时，物体将会破碎。",[11,586,587],{},[499,588,589],{},"Damage Spread",[11,591,592],{},"伤害扩散指数，指定伤害在物体上传递的速度。在应用范围伤害时产生作用，距离伤害产生点为0的将受到所有的伤害，而到达Damage Radio的距离为止，伤害逐渐衰减为0。",[11,594,595],{},[499,596,597],{},"Enable Impact Damage",[11,599,600],{},"开启碰撞伤害，开启之后在与其他物体发生碰撞时将会接收伤害。",[11,602,603],{},[499,604,605],{},"Impact Damage",[11,607,608],{},"碰撞时接收伤害的指数。碰撞所受伤害为这个指数和冲击力的乘积。",[11,610,611],{},[499,612,613],{},"Default Impact Damage Depth",[11,615,616],{},"碰撞伤害产生的破坏深度。在多碰撞深度，有支撑设定的物体进行破坏时很有作用。。",[11,618,619],{},[499,620,621],{},"Custom Impact Resistance",[11,623,624],{},"自定义冲击阻力开关",[11,626,627],{},[499,628,629],{},"Impact Resistance",[11,631,632],{},"自定义冲击阻力。数值越低时碰撞的物体将受到更少的冲击主力，能更轻易的穿过物体。",[11,634,635],{},[499,636,637],{},"Damage Cap",[11,639,640],{},"伤害上限，规定破碎时所承受的最大伤害。大多用于防止冲击破碎被打开时产生的过于巨大的伤害导致破碎效果大于预期。",[11,642,643],{},[499,644,645],{},"Impact Velocity Threshold",[11,647,648],{},"在物体重叠生成时，物理引擎会检测到物体之间巨大的碰撞力。但是实际上两个物体之间的相对速度是很低的，通过设定这个阈值，来屏蔽小于这个值时的碰撞伤害的发生。",[11,650,651],{},[499,652,653],{},"Max Chunk Speed",[11,655,656],{},"当这个值大于0时，碎片的运行速度将会依次为上限。",[11,658,659],{},[499,660,661],{},"Fracture Impulse Scale",[11,663,664],{},"定义物品破碎时碎片在法线方向的受力比例，这个力将会把碎片推离物体。",[11,666,667],{},[493,668,669],{},"Hierarchy Depth",[11,671,672],{},[499,673,674],{},"Support Depth",[11,676,677],{},"支撑深度，高于这个深度的碎片将会拥有非常精细的支撑效果，而低于这个深度的碎片将不会拥有支撑效果。这个设定将会增进运算的复杂度。",[11,679,680],{},[499,681,682],{},"Minimum Fracture Depth",[11,684,685],{},"低于这个深度的碎片将不会被破坏，这样能实现更好的支撑效果。当这个值大于最大破碎深度时，物体将不会破碎",[11,687,688],{},[499,689,690],{},"Enable Debis",[11,692,693],{},"开启碎屑，一些破碎深度很深，也就是很碎的碎片将被视为碎屑。",[11,695,696],{},[499,697,698],{},"Debirs Depth",[11,700,701],{},"碎片被认定为碎屑深度。",[11,703,704],{},[499,705,706],{},"Essential LOD Depth",[11,708,709],{},"只有高于这个深度的碎片才会被视为“重要”的，默认为0表示破碎深度0，即破碎前的物体。",[11,711,712],{},[499,713,714],{},"Depth Parameters",[11,716,717],{},"一个存储EImpactDamageOverride类型的数组，数组序列对应破碎深度。可以用于对碰撞破碎的伤害传递进行重载。",[11,719,720],{},[493,721,722],{},"Debris",[11,724,725],{},[499,726,727],{},"Debris Lifetime Min",[11,729,730],{},"碎屑最短生命周期。当碎屑到达生命周期时将会被系统删除。",[11,732,733],{},[499,734,735],{},"Debris Lifetime Max",[11,737,738],{},"碎屑最长生命周期",[11,740,741],{},[499,742,743],{},"Debris Max Separation Min",[11,745,746],{},"碎屑消亡距离最小值。当碎屑到达消亡距离时将会被系统删除。",[11,748,749],{},[499,750,751],{},"Debris Max Separation Max",[11,753,754],{},"碎屑消亡距离最大值",[11,756,757],{},"每一个单独的碎屑的生命周期和消亡距离都在对应的最小值和最大值之间。",[11,759,760],{},[499,761,762,763],{},"ValidBounds",[764,765,766],"span",{},"min,max",[11,768,769],{},"规定一个范围，当碎屑离开这个范围时将会被删除。",[11,771,772],{},[493,773,774],{},"Effects",[11,776,777],{},[499,778,779,780],{},"Fracture Effects",[764,781],{},[11,783,784],{},"特效设置，每一个元素的Index都对应相应的破碎深度。可以设置粒子以及声音效果。",[786,787],"hr",{},[11,789,790],{},"物体破碎的逻辑相对简单，和游戏逻辑进行结合也很方便。如果和粒子系统结合的话，应该会有更好的效果。",{"title":84,"searchDepth":155,"depth":156,"links":792},[],"2015-06-19",{"layout":170,"status":171,"published":172,"author":795,"author_login":796,"author_email":797,"author_url":798,"wordpress_id":799,"wordpress_url":800,"date_gmt":801,"excerpt":802},{"display_name":796,"login":796,"email":797,"url":798},"chaoshikari","chaoshikari@gmail.com","\u002F",1301,"\u002F\u002F?p=1301","2015-06-19 09:11:01 +0000",{"type":8,"value":803},[804],[11,805,446],{},"\u002F2015-06-19-ue4物体破碎",{"title":441,"description":446},"_legacy\u002F2015\u002F2015-06-19-ue4%e7%89%a9%e4%bd%93%e7%a0%b4%e7%a2%8e",[188,190,810],"破碎","U4xzoxstfihPzy96hFGxGC-roqkl8xBxfzJzj7f_LlU",{"id":813,"title":814,"body":815,"date":1069,"description":819,"extension":168,"meta":1070,"navigation":172,"path":1079,"seo":1080,"stem":1081,"tags":1082,"__hash__":1084},"blogs\u002F_legacy\u002F2015\u002F2015-02-11-apex%e7%9b%b8%e5%85%b3.md","APEX相关",{"type":8,"value":816,"toc":1065},[817,820,823,826,829,834,841,844,847,850,855,858,863,866,869,874,877,882,885,890,893,896,899,902,905,910,916,919,922,927,930,935,938,941,946,949,954,957,962,965,968,971,976,979,984,987,990,995,998,1002,1005,1008,1013,1016,1019,1024,1027,1030,1036,1039,1044,1047,1052,1055,1060,1062],[11,818,819],{},"由于UE4使用的是PhysX引擎，因此一些相关的特性需要使用其相关的工具才能实现。当前（4.6.1）版本UE4只支持两个Apex特性，分别是Destruct和Cloth。",[11,821,822],{},"对官方的讲解视频以及部分文档进行总结，方便以后使用到时可以进行快速的索引。",[28,824,825],{"id":810},"① 破碎",[11,827,828],{},"破碎方面使用PhysX的工具可以获得额外的两种制作方式，同时可以得到当前引擎中没有的多级别破碎效果。",[11,830,831],{},[499,832,833],{},"Slice模式切割",[11,835,836,837],{},"官方视频地址：",[38,838,839],{"href":839,"rel":840,"title":839},"http:\u002F\u002Fv.youku.com\u002Fv_show\u002Fid_XNDEzMTM3Mzky.html",[398],[11,842,843],{},"示例文件目录为PhysXLab目录下的DestructionSamples\\Pillar。",[11,845,846],{},"在文件菜单中选择Import 3D Mesh导入BrickPillar.FBX（其实可以直接打开官方提供的project文件，这样就不用进行文件的导入了）。",[11,848,849],{},"在上面的工具栏中选择刀形状的切割工具，在右边的工具栏就会出现相应的属性。",[11,851,852],{},[227,853],{"alt":229,"src":854},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb.png",[11,856,857],{},"直接点击Fracture按钮或者右上角跳动的F图标，就会生成Slice的破碎",[11,859,860],{},[227,861],{"alt":229,"src":862},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb1.png",[11,864,865],{},"由于没有切面贴图，切面的效果很不理想。因此先在文件菜单中点击Load Texture as Materia来导入材质BrickPillarInt_d.tga。",[11,867,868],{},"导入之后到Graphic工具中应用切面贴图即可。需要注意的是示例提供的贴图应用时和默认的UV Scale有所不同。",[11,870,871],{},[227,872],{"alt":229,"src":873},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb2.png",[11,875,876],{},"在Slice属性中，展开高级模式，可以手动的设置各个坐标上的切割数",[11,878,879],{},[227,880],{"alt":229,"src":881},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb3.png",[11,883,884],{},"通过设置切割深度，可以做出层次更多的切割结果。在工具栏中的预览深度可以调节当前预览的切割效果层次。",[11,886,887],{},[227,888],{"alt":229,"src":889},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb4.png",[11,891,892],{},"其他的一些属性：",[11,894,895],{},"Use Target Proportions - 使得碎片尽量的保持给定的长宽高比例，这个设置会优先于切割线设置来保持比例。",[11,897,898],{},"Seams Variation - 使得切割线的分布变得更加的不均匀，有平移和角度两个选项",[11,900,901],{},"Noise - 有幅度、频率和网格尺寸3个选项，可以使切面表面出现凹凸效果。",[11,903,904],{},"属性之间的组合能够实现不同的材质破碎效果，在编辑器中进行尝试即可。按F12可以进入预览模式，用锤子进行破坏来模拟实际的效果。",[11,906,907],{},[499,908,909],{},"Cut-Out模式切割",[11,911,836,912],{},[38,913,914],{"href":914,"rel":915,"title":914},"http:\u002F\u002Fv.youku.com\u002Fv_show\u002Fid_XMzU1NDY0NTMy.html",[398],[11,917,918],{},"示例文件目录为PhysXLab目录下的DestructionSamples\\Wall。",[11,920,921],{},"这个模式有两个设置的地方，一个是要调整切割的挡板的位置，另外一个是要选择切割图。全部设置过之后会自动生成两个层次的分割效果。第一层是设置好的挡板的分离，第二层是对分离出来的表面应用切割图进一步分割。",[11,923,924],{},[227,925],{"alt":229,"src":926},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb5.png",[11,928,929],{},"生成之后的效果就是完全按照墙面的砖块进行分割破碎。",[11,931,932],{},[227,933],{"alt":229,"src":934},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb6.png",[11,936,937],{},"切面贴图和Noise的设置基本和Slice模式的相同。",[11,939,940],{},"切换到Assets工具栏，在第一层级为后面的墙面设置Dont Frature属性，保证其静态。为前面的墙面设置Dont Damage属性，使得所有的伤害被传递到下一个层级，而不是整个墙面对伤害有响应。在第二层级，设置Support Depth为2，同时打开World Overlap，这样一来砖块就会受到世界的支撑。不会出现不自然的瓦解的情况。",[11,942,943],{},[227,944],{"alt":229,"src":945},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb7.png",[11,947,948],{},"可以对这个分割进行进一步的Slice来达到更好的效果",[11,950,951],{},[227,952],{"alt":229,"src":953},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb8.png",[11,955,956],{},"加上一定的随机之后，砖块就变得可以敲碎了。",[11,958,959],{},[227,960],{"alt":229,"src":961},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb9.png",[11,963,964],{},"可以通过Export Assets导出apb格式的破碎设置供UE4导入。",[11,966,967],{},"导入时先导入网格文件，然后点击生成可破坏网格之后在其中导入apb文件。在UE4中进行快捷测试的步骤：",[11,969,970],{},"首先在可破坏物体中",[11,972,973],{},[227,974],{"alt":229,"src":975},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb10.png",[11,977,978],{},"打开并修改Impact Damage，然后将这个物体拖到地图中。",[11,980,981],{},[227,982],{"alt":229,"src":983},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb11.png",[11,985,986],{},"打开物理模拟和碰撞事件。将物体拖到一定的高度。然后开始模拟，坠落的冲击产生的伤害会使得物体破碎。如果使用的是上面生成的破碎，由于一瞬间产生了很多碎片，并且都在进行物理模拟。很可能会引起卡顿。其实对于小碎片，最好使用粒子效果来替换掉。系统的开销就会大幅度下降了。",[11,988,989],{},"同时，导入apb时切面材质如果没有的话需要手动导入。也可以直接指定成其他的材质。",[11,991,992],{},[227,993],{"alt":229,"src":994},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb12.png",[11,996,997],{},"上面的导入中，第二个材质就是切面材质了。",[28,999,1001],{"id":1000},"衣料","② 衣料",[11,1003,1004],{},"衣料的材质制作NVIDIA官方提供了针对3ds max和maya的插件，虽然官方社区有直接使用Physx自带的制作程序的相关说法。但是还是存在不少问题，这里还是直接使用官方提供的流程进行操作比较好。在NVIDIA官方下载好插件并安装后，可以在目录中看到官方提供的文档。详细的参数及其作用可以到其中去参考。",[11,1006,1007],{},"制作Cloth材质可以在toolbar上点击这个按钮：",[11,1009,1010],{},[227,1011],{"alt":229,"src":1012},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb13.png",[11,1014,1015],{},"这样的话就会在当前修改器栈中添加一个新的衣料材质修改器，可以在其中进行属性的设置等操作。",[11,1017,1018],{},"最主要的属性操作是max distance的喷涂，设定好值之后直接点击按钮即可在材质上喷涂上设定的值。",[11,1020,1021],{},[227,1022],{"alt":229,"src":1023},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb14.png",[11,1025,1026],{},"如果要看模拟的效果，可以直接点击插件提供的模拟按钮。",[11,1028,1029],{},"操作完毕之后可以对衣料材质进行导出。当前版本使用下面的配置可以正常的工作：",[11,1031,1032],{},[227,1033],{"alt":1034,"src":1035},"SNAGHTML8aa3b0","\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002FSNAGHTML8aa3b0_thumb.png",[11,1037,1038],{},"然后就是在UE4中进行导入了，衣料材质不需要导入到内容管理器中。直接在需要使用到的模型中点击下面的添加材质按钮即可。",[11,1040,1041],{},[227,1042],{"alt":229,"src":1043},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb15.png",[11,1045,1046],{},"添加完毕之后就可以在材质的下方看到Cloth的选框，在其中选择对应的即可。",[11,1048,1049],{},[227,1050],{"alt":229,"src":1051},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb16.png",[11,1053,1054],{},"最终的结果如下，由于是静态图片不怎么能看出效果。",[11,1056,1057],{},[227,1058],{"alt":229,"src":1059},"\u002Fwp-content\u002Fuploads\u002F2015\u002F02\u002Fimage_thumb17.png",[786,1061],{},[11,1063,1064],{},"总体而言，作为UE4外部的制作流程，APEX的操作还是相对简单的。",{"title":84,"searchDepth":155,"depth":156,"links":1066},[1067,1068],{"id":810,"depth":156,"text":825},{"id":1000,"depth":156,"text":1001},"2015-02-11",{"layout":170,"status":171,"published":172,"author":1071,"author_login":796,"author_email":797,"author_url":798,"wordpress_id":1072,"wordpress_url":1073,"date_gmt":1074,"excerpt":1075},{"display_name":796,"login":796,"email":797,"url":798},1168,"\u002F\u002F?p=1168","2015-02-11 13:46:43 +0000",{"type":8,"value":1076},[1077],[11,1078,819],{},"\u002F2015-02-11-apex相关",{"title":814,"description":819},"_legacy\u002F2015\u002F2015-02-11-apex%e7%9b%b8%e5%85%b3",[188,190,1083],"APEX","4kaRlxLuoGhZbAs6po6nUVnEZ4T0qvvXWw-Tu2sFeec",{"id":1086,"title":1087,"body":1088,"date":1276,"description":1092,"extension":168,"meta":1277,"navigation":172,"path":1286,"seo":1287,"stem":1288,"tags":1289,"__hash__":1290},"blogs\u002F_legacy\u002F2015\u002F2015-01-31-%e7%89%a9%e7%90%86%e6%a8%a1%e6%8b%9f.md","物理模拟",{"type":8,"value":1089,"toc":1264},[1090,1093,1096,1099,1102,1105,1111,1114,1117,1121,1130,1134,1137,1141,1144,1148,1151,1155,1158,1163,1166,1171,1174,1222,1226,1229,1234,1238,1241,1246,1255,1257,1260],[11,1091,1092],{},"当前UE4使用PhysX3.3作为物理引擎。",[18,1094,1095],{"id":1095},"碰撞体生成",[11,1097,1098],{},"碰撞体的生成方式有三种",[11,1100,1101],{},"第一种是，简单图形碰撞，提供球体、方体和胶囊三种形状的选择。碰撞成本最低，在很多情况下效果也很不错。",[11,1103,1104],{},"第二种是，基于离散定向多面体的生成方式。K-DOP的方式中，K的值越高的话，理论上碰撞的精度就会提高。但是同时的，碰撞的运算量耗费也会提升。官方的配图非常的形象：",[11,1106,1107],{},[227,1108],{"alt":1109,"src":1110},"kdop_sizes.jpg","\u002Fwp-content\u002Fuploads\u002F2015\u002F01\u002Fkdop_sizes.jpg",[11,1112,1113],{},"第三种是凸面碰撞，用的是凸包方法。生成的碰撞图形非常的精确，对于模型不规则又要求精确碰撞的情形比较有效。不过相对的，碰撞成本也非常的高。",[11,1115,1116],{},"游戏预览中可以使用控制台来打开碰撞调试的开关，打开之后可以看到场景中各个物体的碰撞图形。可以方便进行碰撞的调试。",[28,1118,1120],{"id":1119},"physics-constraint","Physics Constraint",[11,1122,1123,1124,1129],{},"物理约束提供物体之间的连接，根据属性的设置不同会有不同的效果。可以指定连接某个物体的组件，当和人物骨架连接时需要指定连接的骨骼名。连接可以设置选择或者拉伸极限。详细设定可以参照",[38,1125,1128],{"href":1126,"rel":1127},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FINT\u002FEngine\u002FPhysics\u002FConstraints\u002FConstraintsReference\u002Findex.html",[398],"文档","在引擎中测试。",[28,1131,1133],{"id":1132},"physics-damping","Physics Damping",[11,1135,1136],{},"阻尼分为线性的和旋转的两种。30的线性阻尼足以使物体在初始化时抵挡9.8的重力而不下落。使得有力量作用的运动物体停止的最小线性阻尼是100。在没有旋转阻尼的情况下，旋转会永远进行下去。而100的旋转阻尼几乎会立刻停止旋转。在物理约束上也可以应用阻尼，使得运动超过约束设定的限度之后得以作出相应。应用于约束的阻尼的主要选项分别是刚度和阻尼。",[18,1138,1140],{"id":1139},"vehicles","Vehicles",[11,1142,1143],{},"UE4文档和范例中提供了专门的汽车演示，游戏中需要要到时可以直接新建一个sample查看官方的实现即可。",[18,1145,1147],{"id":1146},"physical-materials","Physical Materials",[11,1149,1150],{},"物理材质是面向物理模拟的材质。可以设定材质的摩擦系数、反弹恢复系数、密度等一些列基本的物理属性。",[28,1152,1154],{"id":1153},"surface-type","Surface Type",[11,1156,1157],{},"表面类型，可以在代码中用来判别的表面类型枚举。",[11,1159,1160],{},[227,1161],{"alt":229,"src":1162},"\u002Fwp-content\u002Fuploads\u002F2015\u002F01\u002Fimage_thumb1.png",[11,1164,1165],{},"可以在项目属性中设置",[11,1167,1168],{},[227,1169],{"alt":229,"src":1170},"\u002Fwp-content\u002Fuploads\u002F2015\u002F01\u002Fimage_thumb2.png",[11,1172,1173],{},"或者在项目的Config\\DefaultEngine.ini中添加，如果不觉得麻烦的话：",[75,1175,1179],{"className":1176,"code":1177,"language":1178,"meta":84,"style":84},"language-ini shiki shiki-themes github-light-high-contrast github-dark monokai","[PhysicalMaterial.SurfaceTypes]\nSurfaceType1=Glass\nSurfaceType2=Metal\nSurfaceType3=Wood\nSurfaceType4=Concrete\n...\nSurfaceType30=CollapsedStar\n","ini",[82,1180,1181,1188,1193,1198,1204,1210,1216],{"__ignoreMap":84},[764,1182,1185],{"class":1183,"line":1184},"line",1,[764,1186,1187],{},"[PhysicalMaterial.SurfaceTypes]\n",[764,1189,1190],{"class":1183,"line":155},[764,1191,1192],{},"SurfaceType1=Glass\n",[764,1194,1195],{"class":1183,"line":156},[764,1196,1197],{},"SurfaceType2=Metal\n",[764,1199,1201],{"class":1183,"line":1200},4,[764,1202,1203],{},"SurfaceType3=Wood\n",[764,1205,1207],{"class":1183,"line":1206},5,[764,1208,1209],{},"SurfaceType4=Concrete\n",[764,1211,1213],{"class":1183,"line":1212},6,[764,1214,1215],{},"...\n",[764,1217,1219],{"class":1183,"line":1218},7,[764,1220,1221],{},"SurfaceType30=CollapsedStar\n",[28,1223,1225],{"id":1224},"physics-sub-stepping","Physics Sub-Stepping",[11,1227,1228],{},"如果打开这个功能，物理模拟会在一个与游戏逻辑独立的线程中运行。这样在同一帧中就能够就行多次物理演算，其结果是，物理模拟会变得更加的精确和真实。但是对系统资源的消耗也会同步上升。",[11,1230,1231],{},[227,1232],{"alt":229,"src":1233},"\u002Fwp-content\u002Fuploads\u002F2015\u002F01\u002Fimage_thumb3.png",[28,1235,1237],{"id":1236},"destructible-mesh","Destructible Mesh",[11,1239,1240],{},"可破坏的网格，在任意一个网格物体上点击右键即可创建可破坏的网格物体",[11,1242,1243],{},[227,1244],{"alt":229,"src":1245},"\u002Fwp-content\u002Fuploads\u002F2015\u002F01\u002Fimage_thumb4.png",[11,1247,1248,1249,1254],{},"破坏网格在接受到伤害事件后就会破碎，详细的文档在",[38,1250,1253],{"href":1251,"rel":1252},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FINT\u002FEngine\u002FPhysics\u002FDestructibles\u002FDestructibleProperties\u002Findex.html",[398],"这里","。想要做出复杂的破坏效果的话，需要用到NVIDIA的Apex。",[786,1256],{},[11,1258,1259],{},"物理模拟部分大体上就是这些了，如果要做出华丽的效果还需要和粒子系统、音效进行配合。毕竟物理引擎只是对真实环境进行模拟，很多地方还是要依靠代码来进行的。",[1261,1262,1263],"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":84,"searchDepth":155,"depth":156,"links":1265},[1266,1270,1271],{"id":1095,"depth":155,"text":1095,"children":1267},[1268,1269],{"id":1119,"depth":156,"text":1120},{"id":1132,"depth":156,"text":1133},{"id":1139,"depth":155,"text":1140},{"id":1146,"depth":155,"text":1147,"children":1272},[1273,1274,1275],{"id":1153,"depth":156,"text":1154},{"id":1224,"depth":156,"text":1225},{"id":1236,"depth":156,"text":1237},"2015-01-31",{"layout":170,"status":171,"published":172,"author":1278,"author_login":796,"author_email":797,"author_url":798,"wordpress_id":1279,"wordpress_url":1280,"date_gmt":1281,"excerpt":1282},{"display_name":796,"login":796,"email":797,"url":798},1126,"\u002F\u002F?p=1126","2015-01-31 15:17:49 +0000",{"type":8,"value":1283},[1284],[11,1285,1092],{},"\u002F2015-01-31-物理模拟",{"title":1087,"description":1092},"_legacy\u002F2015\u002F2015-01-31-%e7%89%a9%e7%90%86%e6%a8%a1%e6%8b%9f",[188,190],"e84-jjijwAB6dEac9QTh7MW51RS5Wak5_-CBsED1OXI",1788763179539]