havok引擎文档翻译 之 性能优化

1.优化集成性能

优化仿真岛的建立过程

Use the VDB's simulation island viewer to examine the number and size of all the islands (both active and inactive) in the world at any time.

 

使用VDB的模拟岛查看器 来测试任何时间整个场景的所有(活跃和非活跃)仿真岛的个数和大小!

The biggest potential bottleneck during the integration step is if all the simulated objects end up in a single large simulation island. This 

 

prevents any multithreading of the integration step

在集成阶段,最大的潜在瓶颈就是,所有的模拟对象都在一个仿真岛上,那么多线程就完全没用了!

 At the other end of the spectrum, having too many simulation islands (in relation to the number of simulated objects) can be bad as it will 

 

add extra (and unnecessary) processing overhead

另一种极端情况就是,有太多的模拟岛,它会增加额外的处理开销!

 Ideally, we only want as many active simulation islands as we have available threads, and usually not many more than that. Unfortunately, 

 

tweaking the exact number of islands is not directly exposed to the end user as any overlapping pairs of bodies will automatically merge 

 

their respective islands.

实际上,我们只希望我们的模拟岛数和线程数相当,并且不要超过太多!不幸的是,并没有可以直接控制模拟岛个数的接口给用户,因为任何重叠的物体相关的

模拟岛会自动合并!

We do however have some control on how separate islands are merged together. This is governed by the hkpWorldCinfo::m_minDesiredIslandSize 

 

parameter. When set to its default (64), it will maintain sparse islands that contain 64 or less bodies. It will only potentially split them 

 

if there are more than 64 bodies. If your simulation world contains few dynamic objects, it is a good idea to reduce the value of this 

 

parameter. This will allow the creation of more islands where possible, making the best use of multiple threads.

无论如何,我们都有一些控制方法来确定如何合并不同的模拟岛,这个方法是用hkpWorldCinfo::m_minDesiredIslandSize这个参数来控制!默认情况下,它的

值是64,它可以控制我们分成64或者更少的模拟岛数,它只会在你的场景中多于64个物体时,将这些物体分裂,如果场景中没有64个以上物体的话,最好根据物

 

体数来设置这个参数,它允许建立更多的模拟岛,最好使用多线程!

 

3.1.2. Rigid Body Deactivation 刚体停用!

Another way to optimize integration performance is to minimize the number of objects simulated in every frame, by ensuring that objects 

 

deactivate quickly. 

另一种优化性能的方法是,最小化每帧模拟的物体个数,方法是确保物体会尽快的设置 Deactivation 状态!

The topic of activation and deactivation has been covered in an earlier section. In summary, inactive objects do not partake in 

 

integration/solve/collide steps, so we want to make sure that objects are not kept active unnecessarily.

 

 activation deactivation状态我们之前讨论过,总的来说,deactivation状态的物体不会经过integration/solve/collide这些步骤,所以我们希望确保不必要的活跃状态!

Use the VDB's simulation island viewer to look for any islands that are active (colored green) but where none of its bodies appear to be moving.

使用VDB 模拟岛查看器,来查看处于活跃状态的岛,但是岛中的所有物体都没有移动!来发现问题!

Often, bodies are not deactivated because the deactivation settings are too low. Setting the deactivation distance parameter (hkpWorldCinfo::m_deactivationReferenceDistance) too low, or simply not enabling deactivation on the body (hkpRigidBodyCinfo::m_solverDeactivation) can cause the bodies to remain active and simulated even though they essentially have no effect.

通常,物体没有处于deactivated 状态,是因为deactivation 的设置太低了,这些会导致物体即使没有运动也处于active 状态!

The other common mishap is to call setPosition or setTransform or applyHardKeyframe (and so on) with the same object positions or zero forces every frame. Calling methods that affect a body's transform will always activate that body (or more precisely prevent the body from deactivating), regardless of whether the body's transform is actually changing or not. It is a good practice to wrap all calls to those functions with user versions that exit early if the call won't have any effect.

另一种问题就是,使用lsetPosition or setTransform or applyHardKeyframe 这些接口,给物体设置同样的位置或者0的作用力,这些接口的调用会激活物体,所以如果没有必要的话,不要调用这些接口!

 

 

 

 

 

 

 Optimizing Broad Phase Performance  broad phase阶段优化!

The job of the broad phase is to quickly find pairs of AABBs that are intersecting, and thus to identify pairs of objects that require narrow phase collision detection. The hkpBroadphase class provides functions for adding, removing, and updating objects in the broad phase. These are used by the Havok world when you add, remove, or move entities in the simulation.

Broad阶段的任务是快速找到相交的AABB对,并以此确定要进入narrow phase的碰撞检测对,hkpBroadphase 这个类提供了增加,删除,更新物体到broad阶段的接口,用于增加,减少,更新这个阶段模拟的实体

The VDB's broad phase viewer can be used to examine the broad phase AABBs of the world and all of the dynamic bodies within it.

VDB broad phase viewer可以用于检测这个阶段 所有动态物体的AABB

3.2.1. Configuring the Broadphase for 3-Axis Sweep and Prune Variants

配置Broadphase阶段的sweepand prune 变量

For all broad phase types except hkpWorldCinfo::BROADPHASE_TYPE_TREE, a badly-configured collision detection broad phase can have serious performance implications. As part of setting up your Havok world, you need to specify the dimensions of the broad phase. This requirement is due to various speed and memory optimizations performed internally. You can explicitly set broad phase dimensions in hkpWorldCinfo or by using the hkpWorldCinfo::setBroadPhaseWorldSize() function (default size is 1000 world units):

除了hkpWorldCinfo::BROADPHASE_TYPE_TREE之外的其他所有broad phase类型,配置错误的碰撞检测会导致严重的性能问题,作为建立havok世界的一部分,你必须指定 broad phase的尺寸,这个需求取决于不同的速度和内存优化程序,你可以明确的设定 broad

Phase 的尺寸,在hkpWorldCinfo 中,或者使用hkpWorldCinfo::setBroadPhaseWorldSize() 函数(默认值是1000的时间单位)

There are three important points to consider when setting the size of the broad phase:

Make the broad phase large enough to encompass the whole scene.

Do not make it excessively larger than it needs to be.

Use callbacks to be notified when objects leave the scene.

当设置broad phase的尺寸的时候,有三个重要的点要考虑:

1.保证 broad phase足够的大,可以包含整个场景!

2.不要设置的比需要的大太多了

3.当物体离开场景的时候,要有回调通知

Because the broad phase world has a definite size, it is possible to position objects so that they are outside the broad phase. This must be avoided. During broad phase evaluation, objects outside the broad phase are projected onto the broad phase AABB (it clips the object AABB to the broad phase AABB, in effect reducing the 3D overlap test to a 2D one, producing spurious overlaps). This incurs a significant performance cost as the relevant pairs are all passed to the narrow phase, greatly increasing the amount of work the narrow phase has to do. It also produces incorrect callbacks from other broad phase listeners, and from broad phase raycasts.

因为broad phase世界有一个确定的大小,就可能产生不在broad phase内的对象,这个要绝对避免。在broad phase评估期间,broad phase之外的物体投射到 broad phaseaabb,这个产生显著的性能消耗在相关的对到了narrow phase的时候,大大的增加了narrow phase阶段的工作量,同样在 broad phase的监听器和光线追踪哪里产生不正确的回调

For example, if 100 objects are placed along the x-axis all outside the broad phase, in a line but separated then all their AABBs will be clipped to have the same min and max x-extents. That is, their AABBs each collapse to a rectangle, so the broad phase considers them to be overlapping each other on the X-axis. If the objects' AABBs actually overlap on the other two axes then all 100 objects will be considered to overlap with each other. This will cause (100*99)/2 = 4950 agents to be created, even though most of these will return no collisions when the narrow phase is processed! Collision detection will still work accurately, but it will be massively inefficient both in speed and memory consumption.

例如,如果100个对象被放置在broad phase沿x轴以外,在一条线上,但分离的,那么所有的AABB将被剪切为具有相同的最小和最大x盘区。也就是说,他们的AABB产生的矩形,使broad phase,认为他们能够在X轴互相重叠。如果对象的AABB在另外两个轴也重叠,那么所有的100的对象都将被认为是彼此重叠的。这将导致(100 *99/2=4950代理被创建,即使大部分将返回没有冲突时,在narrow phase碰撞检测仍将准确,但它会是大量低效的,无论是在速度和内存消耗。

To avoid this, ensure that your broad phase world size is appropriate for your scene, and remember the broad phase limits when moving your objects. It is also important that you do not set the broad phase size too large, as internally the broad phase has to quantize the whole range. Too large a broad phase size leads to reduced accuracy in the overlap tests resulting in more narrow phase tests than needed.

为了避免这样的情况发生,确保你的 broad phase world 大小与你的场景大小匹配,并牢记broad phase的限制当移动你的物体的时候,同样你不要把broad phase size设置的太大,broad phase内部有量化的整个范围。太大了broad phase尺寸在重叠导致更窄相比需要测试的测试精度降低。

To monitor objects leaving the broad phase during run-time, you can use the hkpBroadPhaseBorder class in the hkpDynamics. Its maxPositionExceededCallback() method is called whenever an object leaves the broad phase AABB. By default, it removes the entity from the world, but you can implement your own custom handling solution.

为了在游戏中监控物体离开broad phase,你可以使用hkpBroadPhaseBorder class in the hkpDynamics,当物体离开broad phase的aabb的时候,会调用maxPositionExceededCallback方法,默认的是,他会移除物体,但是你可以实现自己的操作。

This callback is triggered from within the multithreaded sections of the engine. The order of callbacks is by default nondeterministic. However, they can be postponed until the end of the simulation step. In that case they will be sorted and triggered in deterministic order. To use this option enable the hkpWorldCinfo::mtPostponeAndSortBroadPhaseBorderCallbacks flag.

这个回调是在引擎的多线程部分被触发的,默认情况下,回调的序列是不确定的,无论如何,他们可以被推迟到模拟的最后一步,在这种情况下,他们将进行排序和确定性的顺序触发。要使用这个的话,要启动hkpWorldCinfo::mtPostponeAndSortBroadPhaseBorderCallbacks这个设置。

3.2.2. Configuring the Tree/Hybrid Broadphase

配置树/混合 broad phase

The tree broad phase automatically performs incremental optimization on each update. To start with an optimal structure you should call hkpTreeBroadPhase::fullOptimize() before the first frame, and after most entities have been registered.

每次更新的时候,树形broad phase会进行自动的增量优化,要启动一个最佳的结构,你需要在第一帧之前,所有实体被注册之后,调用hkpTreeBroadPhase::fullOptimize() 

The following functions can be used to further fine tune performance:

以下函数可用于进一步的微调性能:

compact() will rearrange the memory layout of the tree broad phase to improve cache efficiency. The impact on performance is especially important for PlayStation®3 SPU queries.

Compact将会重新排列broad phasetree的内存布局,来提示缓存效率,它对ps3 spu查询的效率影响尤其重要

setJitterMargin(hkReal margin) sets the width of the margin added around entities when registered in the broad phase. This margin allow for an entity to move slightly (jitter) without triggering an update of the underlying acceleration structure. The default value is 0.01m (1 centimeter), higher values will improve the broad phase update performance but decrease query speed.

setJitterMargin(hkReal margin) 

这个margin允许实体晃动,而不触发底层的加速结构体更新,默认值是0.01,更大的值可以提高更新的性能,但是会降低查询的性能

setMotionPredictionFactor(hkReal factor) sets the factor used for motion prediction. Motion prediction will attempt to predict a moving entities position (up to factor * physicsDeltaTime). If the entity position is correctly predicted, it will not trigger the update of the underlying acceleration structure. The default value is 2.0, that is, attempt to predict two time steps into the future. Higher values will improve the broad phase update performance but decrease query speed.

 

setUpdateQuality(hkReal factor) sets the number of entities (as a factor of the total number of entities registered in the broad phase) to update each frame. The default value is 1/60, that is, 100% of the entities will have been optimized after 60 frames. Higher values will decrease the broad phase update performance but increase the query speed. Note that this function can be called with a different value each frame so the quality could, for instance, be made proportional to the current frame rate.

setCacheQuality(int passes) sets the number of cache optimization passes executed at each update, which behaves like an incremental version of the compact() method.

 Limiting the Number of Objects

The cost of simulating the broad phase increases with the number of objects in the scene. Specifically, as the number of objects in the broad phase grows, the cost of inserting objects, removing objects, and querying the broad phase (for raycasts etc.) increases linearly. However, the cost of colliding objects increases at a slower rate -- the simulation is optimized to simulate collision detection as fast as possible.

broad phase的消耗随着场景中的物体个数而增加,随着 broad phasezhong物体的增加,插入物体,移除物体,查询都会线性增加,

 

It is recommended to keep the number of objects in the broad phase as low as possible. Due to the fact that inserting and removing objects increases in costs with the number of objects, maintaining a stable number of objects is also encouraged. In a scene with a large number of objects with few ray casts and little to no object insert/removal, the collision detection will remain very optimal.

物体数量越少越好,同样因为增加和移除成本,所以保持稳定的物体数量也是很好的,大场景中有少量的光线碰撞和少量的增删操作,碰撞检测降低优化将会比较好

A simple way of reducing the number of bodies in the broad phase is by combining multiple objects into one. In particular, the BV Compressed Mesh Shape and the Extended Mesh Shape provide the ability to insert fixed world objects into the landscape shape.

一个好的显示物体数量的方法是合并多个物体,the BV Compressed Mesh Shape and the Extended Mesh Shape提供方法可以把静态的物体合并到地表中

If the simulated scene is large in relation to the area of current player interest, it can be a good strategy to remove objects from the simulation if they are outside of the area of interest.

3.2.4. Collision Tolerance 碰撞公差 默认值是0.1

1.这个距离可以尽早的防止渗透,即使是高速运行的物体,从而减少collision slover的工作,

2.它同样在物体轻微分离的时候保持碰撞信息,当一个物体在另个物体上滑动或者沉淀,它允许物体保持同样的信息而不是每帧都重新计算

 

Optimizing Narrow Phase Performance 优化Narrow Phase 性能

In this section we discuss tips that can improve the performance the simulation when dealing with individual shape collision detection and resolution. These tips focus primarily on how to tweak the properties of shapes and bodies to improve performance.

这里我们讨论如何提高单独shape的碰撞检测和方案

Use the VDB timers (and "stat graph overlay") to examine the time spent in narrow phase collision

使用VDB Timers可以检测narrow phase的时间消耗

3.3.1. Convex Shape Radius 凸形半径

As mentioned in the shapes section, the hkpConvexShape class has a radius member that adds an extra "shell" to any convex shape except for the sphere and the capsule. For a sphere and a capsule, the convex shape radius actually defines the radius of the sphere and the capsule, respectively, although it is treated by the collision detector in exactly the same way. The sphere is just a "point", and the extra "shell" is the radius of the sphere.

The convex radius of objects can be viewed at any time using the hkpConvexRadiusViewer in the VDB and/or the demo framework.

shape章节提过,每个hkpConvexShape 类有一个半径,可以增加多余的壳给任何 凸状物体,除了球和胶囊之外,对于球和胶囊来说,convex shape radius 实际上定义了球和胶囊的半径,个别的,虽然在碰撞检测处理中基本上是同样的方式,球只是一个点,而壳是球的半径。

By default, an hkpConvexShape's radius value is 0.05.

默认的是,hkpConvexShape's 的半径是0.05

 

This shell is used as the shape's surface for collision detection. It increases the collision volume of the shape by the specified radius. The collision simulation will treat all objects with this radius as having an extra thickness.

这个壳被用来当做碰撞检测的表面,它根据指定的半径增加了碰撞体的大小,碰撞模拟会当做物体增加了一个指定的厚度

Adding a shell affects where the surface of the object is in the simulation, and where the object will come to rest. For instance, if a box with a shell comes to rest on a table, there will appear to be a small visible gap between the box and the table, as in the next illustration.

增加一个壳会影响物体的表面模拟,比如,当有壳的盒子放在桌子上的时候,看起来盒子和桌子之间有一个小的空隙。像下图一样

However, as far as the collision solver is concerned, the two objects are in direct contact, as shown below.

即使碰撞solver执行过之后,两个物体仍像下图一样。

Why use a radius? Adding a radius to a shape can improve performance. The core convex-convex collision detection algorithm is fast when shapes are not interpenetrating, and slower when they are. Adding a radius simply makes it less likely that the shapes themselves will interpenetrate, reducing the likelihood of the slower algorithm being used.

为什么要使用这个半径呢?增加一个半径可以提升性能,当物体没有相交的时候凸-凸碰撞检测算法会更高效,增加一个半径使得交叉的几率更小,控制低速算法的使用率

The shell is thus faster in situations where there is a risk of shapes interpenetrating - for instance, when an object is settling or sliding on a surface, or when there is a stack of objects, or when many objects are jostling together.

这个半径可以在可能外形交叉的情况下加速,比如,当一个物体放在或者滑动在一个表面的时候,或者堆了很多东西,或者很多东西堆在一起。

Raycasting against objects with the radius will also cast against that expanded surface. However, raycasting against triangles does not raycast against the expanded form as it is computationally prohibitive, but as triangle based objects are normally landscapes that usually have zero radius, it is not normally an issue. It is ok for landscapes to have zero radius, because we only need to ensure that any two interacting bodies have some extra radius between them. As long as all dynamic bodies have an extra radius, the extra radius on a stationary landscape is not necessary.

如果所有动态物体都有一个额外半径,那么静态地面的多余的半径就不需要了。

If a small shell interpenetration occurs, as shown in the next diagram, the system will work to restore the gap, the fast algorithm will still be used, and, as shown, the box will still not have appeared to penetrate the table.

当小的可渗透发生的时候,系统将恢复gap,快速算法将被使用,如图,box仍然没有穿透桌子

Convex Vertices Shapes and the Convex Shape Radius凸顶点形体,和凸形体半径。

. Visual Implications of Convex Radius

Implications of Using Transform Shapes

Transform Shape使用要注意,有可能会导致性能损失!

 

3.3.3. MOPP Fit Tolerance 适配公差 

When using a MOPP tree, you can customize the tolerance (called the fit tolerance) that describes how closely the bounding volumes at the leaf nodes (and the internal nodes) approximate the ideal bounding volume. This is done using the hkpMoppCompilerInput structure, which you pass to the hkpMoppUtility::buildCode() function when building the MOPP.

当使用MOPP树的时候,你可以配置合适的公差来描述叶子节点的包围体和合适的包围体,这个使用hkpMoppCompilerInput 结构体来配置,当构建MOPP的时候通过hkpMoppUtility::buildCode() 来做。

The hkpMoppCompilerInput structure allows you to choose what is most highly optimised: the size of the tree, or how closely the leaf nodes bound the triangles. The effects of changing the fit tolerance involves a tradeoff between performance and memory:

hkpMoppCompilerInput 结构体允许你选择最优的方案,树的大小,叶子节点包围三角形时的接近程度,改变适配公差可以提升性能和内存之间的权衡。

 The smaller the fit tolerance, the less triangles are passed to the narrow phase collision detector and the less processing is needed.

适配公差越小,越少的三角形会被传到narrow phase的碰撞检测,处理的事情越少。

However, the smaller the fit tolerance of the bounding volumes, the more memory is needed to store the bounding volume information

同样,包围盒的适配公差越小,越多的内存就需要用于存储包围体信息

For a detailed description of the parameters of the MOPP fit tolerance and background information on the MOPP please consult the hkpMoppCompilerInput section in the Reference Manual.

关于mopp适配公差和背景信息细节的描述可以从hkpMoppCompilerInput section 查看

3.4 优化多线程性能

There are several issues that can affect multithreaded performance, but they broadly fall into two separate categories: job distribution and concurrent access to data.

有多个为可以影响到多线程的性能,但他们可以划分到两个大的方面:工作分配和数据的并发访问。

3.4.1Optimizing Job Distribution 优化工作分配

性能问题:时间步长结束的时候,线程花了大量的空转时间。

在模拟步骤的主要部分完成之后,havok处理所有的TOI事件,TOI事件,通常放在一个单独的线程中处理,除了碰撞检测可以用多线程处理。

多线程作业要匹配需要处理的碰撞的权重。 hkpWorldCinfo::m_maxEntriesPerToiCollideTask 指定了单一工作可以处理的条目的最大数量,调整这个参数将有助于实现一个特定的模拟场景的最佳性能。

If hkpWorldCinfo::m_maxEntriesPerToiCollideTask is low and agent entries only contain simple agents (for example a scene of many small dynamic objects using the sphere-sphere agent), then the engine will spend much more time synchronizing and managing collision jobs on the queue then it will spend doing actual collision detection work. Adjust this value upwards when dealing with many simple collisions.

如果这个值太低

If hkpWorldCinfo::m_maxEntriesPerToiCollideTask is too high, and the collisions tend to involve complex cases (such as list shapes against complex landscape), then a single thread may be stuck with processing all the collision queries. Adjust this value downwards when dealing mainly with complex collisions.

如果这个值太高,单线程会用于处理所有的碰撞查询

If the problem involves tiny collision jobs being multithreaded, you can turn TOI multithreading off entirely by setting hkpWorldCinfo::m_processToisMultithreaded to false.

 

Performance problem: Too many small simulation islands性能问题:太多的小模拟岛

3.4.2. Minimizing Concurrent Access of Data减少数据的并发访问

There are a number of small tips to remember when minimizing the number of concurrent accesses of data:

这里有一系列的提示来减少数据的并发访问

In general, batching collision information queries (such as linear casts) will improve concurrency issues by pooling common data together. Batching is also a generally good practice to maximize the performance of any multithreaded platform.

总的来说,批量碰撞信息查询会增加并发问题。

You should not need access to write-locks when using Havok Physics, but is a generally a good idea to use the hkpWorld::markForRead() and hkpWorld::markForWrite() methods to verify that you are not accesssing data at the wrong times.

使用havok physics的时候不需要方位写锁,而是用hkpWorld::markForRead() and hkpWorld::markForWrite() 

Minimizing the use of contact callbacks is also strongly advised as they are a great source of concurrency issues.

越少使用 contact callbacks越好。他们是并发问题的重要来源

The earliest you can discard a potential collision between two objects you should do so. As much as possible, we should try to discard collisions in using the collision filtering system. Unwanted collisions should not be filtered out in contact point callbacks or in collectors (for asynchronous queries), unless you are truly unable to decide whether to discard the collision before it happens.

越早剔除两个可能碰撞的物体越好

3.5 Optimizing Query Performance 优化查询性能

There are several factors that can affect the performance of queries, including those mentioned in the previous optimization sections. In general, we recommend the following tips to address any query performance issues:

有以下优化方法:

Use a less populated broad phase: world queries will perform faster when there are fewer objects to test in the broad phase, especially when using the sweep-and-prune broad phase alone.

当broad phase世界中之有少量需要测试的物体时,更快!特别是单独使用sweep-and-prune broad phase的时候

 

Use phantoms: make use of phantoms to limit the breadth of the queries being performed. The smaller the area that has to be tested the faster the broad phase part of the query will perform. It is much cheaper to limit the test of a raycast to a single room in a building then to test the entire broad phase.

使用phantoms可以限制执行的查询的宽度,区域越小,速度越快,当宝光线追踪限制在一个单独的屋子内的时候,比整个楼的速度快的多。

Use multithreading: leverage the multithreading utilities provided by Havok whenever possible, and especially when performing a significant number of queries. Ideally, design your logic such that you can dispatch jobs to other threads at some point in the frame and collect the results of those jobs later when you need them.

利用多线程的实用程序尽可能Havok的,尤其是当执行一个显着数量的查询。在理想的情况下,设计你的逻辑,你可以派遣就业机会给其他线程在一些点在框架和收集的结果,这些工作以后,当你需要他们。

Batch queries: again, if performing a large number of queries, try to batch the queries together to leverage the spatial caching abilities of the Havok broad phase, and reduce the job management overhead if using multithreading.

批量查询:再次,如果进行大量的查询,尝试批量查询利用Havok的博大相空间的缓存能力,并减少作业管理开销,如果采用多线程。

Also refer to the OptimizeWorldRaycastDemo, which illustrates a number of these techniques.

posted @ 2013-09-11 19:58  鱼写代码  阅读(426)  评论(0编辑  收藏  举报