This document is about: QUANTUM 2
SWITCH TO

Queries

概述

查詢可以考慮動態實體及靜態碰撞器。針對射線、線及形狀重疊的API非常相似,其總是會導致一組命中集合(在它們的欄位中有相同種類的資料)。

查詢

線投射及射線投射

C#

// For 2D
var hits = f.Physics2D.LinecastAll(FPVector2.Zero, FPVector2.One);
for (int i = 0; i < hits.Count; i++) {
    var hit = hits[i];
}

// For 3D
var hits = f.Physics3D.LinecastAll(FPVector3.Zero, FPVector3.One);
for (int i = 0; i < hits.Count; i++){
    var hit = hits[i];
}

結果命中集合物件,含有以下屬性:

  • 命中集合 中的各個物件持有一個實體參照或靜態碰撞器資訊。它們互相排斥——一個有效,另一個就 無效
  • 計數 應該總是用於迭代 命中集合;及,
  • 沒有排序命中。您可以調用Sort()並且在一個 FP向量2 中傳送,來排序它們,這將導致命中根據其到提供給函數的參照點的距離進行排序。

射線投射是線投射的語法糖。它們作用相同而只需要一個 開始方向最大距離 而不是 開始結束。此外,您可以傳送這些選擇性的參數到線投射及射線投射:

  • 圖層遮罩,以指定哪個物理圖層來被執行投射;及,
  • 查詢選項,以指定投射中考量的碰撞器類型。

形狀查詢

Quantum支援兩種不同的形狀查詢類型:

  • 形狀重疊;及,
  • 形狀投射(從v2.1開始)。

這些可以用於所有Quantum中支援的動態形狀。

請注意: CompoundShapes可用於執行形狀查詢。如需更多資訊,請閱讀 形狀設定 頁面。

形狀重疊

OverlapShape()傳回一個 命中集合。所需的參數為:

  • 一個中心位置(FP向量2FP向量3);
  • 一個旋轉(FPFPQuaternion 以針對3D等位);及,
  • 一個形狀(形狀2D形狀3D——可能來自一個 物理碰撞器,或在調用時建立)。

C#

// For 2D
var hits = f.Physics2D.OverlapShape(FPVector2.Zero, FP._0, Shape2D.CreateCircle(FP._1))
for (int i = 0; i < hits.Count; i++){
    var hit = hits[i];
}

// For 3D
var hits = f.Physics3D.OverlapShape(FPVector3.Zero, FPQuaternion.Identity, Shape3D.CreateSphere(1));
for (int i = 0; i < hits.Count; i++){
    var hit = hits[i];
}

形狀投射

形狀投射(2D及3D)從Quantum 2.1開始可用。

ShapeCastAll()傳回一個 命中集合。所需的參數為:

  • 中心位置(FP向量2FP向量3);
  • 形狀的旋轉(FPFPQuaternion 以針對3D等位);
  • 形狀指標(_形狀2D* _ 或 形狀3D* ——可能來自一個 物理碰撞器,或在調用時建立);及,
  • 表示為向量的距離及方向(FP向量2FP向量3)。

C#

// For 2D
var shape = Shape2D.CreateCircle(FP._1);
var hits = f.Physics2D.ShapeCastAll(FPVector2.Zero, FP._0, &shape, FPVector2.One);
for (int i = 0; i < hits.Count; i++){
    var hit = hits[i];
}

// For 3D
var shape = Shape3D.CreateSphere(1);
var hits = f.Physics3D.ShapeCastAll(FPVector3.Zero, FPQuaternion.Identity, &shape, FPVector3.One);
for (int i = 0; i < hits.Count; i++){
    var hit = hits[i];
}

它使用一個自訂GJK基礎的演算法。GJK設定在SimulationConfig資產的Physics > GJKConfig節中可用。設定允許平衡準確性及效能,正如兩者都有它們的取捨。預設值被平衡,以適應常規大小的形狀。

  • Simplex Min/Max Bit Shift:透過逐步移動點的原始值,避免變質情況,不會犧牲物理空間中的位置有效範圍,來允許Voronoy單工中的點的更好的精確度。如果涉及的形狀的比例和/或它們之間的距離非常小,可考慮增加此值。
  • Shape Cast Max Iterations:搜尋硬容錯之下的解決方案時,演算法執行的最大迭代數量。增加它可能導致更準確的結果,在最糟糕的情況將犧牲效能,反過來則導致更不準確的結果也增加效能。
  • Shape Cast Hard Tolerance:低於此閾值的一個迭代結果(形狀之間的最近距離)可作為完成情形。減少它可能導致更準確的結果,但帶來更多迭代的成本,反過來則導致更不準確的結果也減少迭代的成本。
  • Shape Cast Soft Tolerance:如果在允許的最大迭代次數內未找到低於已定義的硬容錯的可接受結果,且如果目前為止找到的最佳結果低於此軟閾值,則一個形狀投射解決方法仍將傳回正值。在這些情況下,增加此閾值將增加誤判為正的幾率,而減少它將增加誤判為負的幾率。

排序命中

可以排序所有傳回一個HitCollection的查詢。

  • Sort():在2D中取得一個FP向量2,以及在3D中取得一個FP向量3,並且根據命中到提供的點的相對距離來排序集合。
  • SortCastDistance():用於排序ShapeCast查詢的結果。它不接受引數,並且根據投射距離來對命中進行排序。

選項

所有查詢,包含它們的廣相位版本,可使用QueryOptions 以自訂操作及其結果。QueryOptions建立一個遮罩,其篩選被考量的物件類型及將被計算的資訊。您可以使用二進位|運算子來結合這些。

命中法線

為了提供最有效能的查詢,所有預設查詢只檢查兩個形狀是否重疊。

為了收到額外資訊,將需要更多計算,其也相對建立更多額外負荷;因此需要您透過傳送ComputeDetailedInfo作為查詢選項參數,來特別指定它。這將啟用命中的計算:

  • 法線
  • 穿透

針對射線三角形檢查,法線總是三角形的法線。因為這被快取在三角形資料之中,所以在這種情況下沒有額外的計算。

篩選命中

以下QueryOptions允許您定義查詢使用的遮罩。如果一個物件沒有匹配指定為參數的QueryOptions,它將被略過;只有匹配QueryOptions的物件將被評估及在結果中傳回。

  • 命中靜態 :只將命中靜態碰撞器

  • 命中運動學 :將命中符合以下情況的實體:

    • 有著一個物理碰撞器且 沒有 物理主體的實體
    • 有著一個物理碰撞器且一個 停用的 物理主體的實體
    • 有著一個物理碰撞器且一個 運動學的 物理主體的實體
  • 命中動態 :只將命中有著一個 啟用的非運動學的 物理主體的實體

  • 命中觸發 :必須與其他旗標 結合 使用以命中觸發碰撞器。

  • 命中所有 :將命中所有有著一個物理碰撞器的實體

預設下,一個查詢將使用HitAll選項。選擇任何其他選項將節省運算。

廣相位查詢

Quantum提供了一個插入物理查詢(射線投射及重疊)的選項,其在物理系統中被解決。為此,您需要:

  1. 建立一個系統。
  2. 當新增它到SystemSetup.cs時,在Core.PhysicsSystem之前插入它。
  3. Core.PhysicsSystem之後運行的任何系統中擷取資訊。

這個設定得益於物理步驟的平行解決方案,這使得它比物理之後的正常查詢速度快得多。

C#

  public static class SystemSetup {
    public static SystemBase[] CreateSystems(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
      return new SystemBase[] {

        // pre-defined core systems
        new Core.CullingSystem2D(),
        new Core.CullingSystem3D(),

        // Placing systems scheduling Broadphase queries here
        // allows them to benefit from the CullingSystems on predicted frames.
        new ProjectileHitQueryInjectionSystem(),

        new Core.PhysicsSystem2D(),
        new Core.PhysicsSystem3D(),

        new Core.NavigationSystem(),
        new Core.EntityPrototypeSystem(),

        // user systems go here
        // This is also where systems retrieving the results of broadphase queries go
        new ProjectileHitRetrievalSystem(),
      };
    }
  }

請注意: 有時廣相位查詢也稱為已插入查詢或已排程查詢,因為它們在求解運行之前被排程/插入到物理引擎中。

插入查詢

您可以從任何在物理之前運行的主要執行緒系統來插入一個查詢。已插入查詢將傳回一個以0為基礎的索引,使用這個相同的索引,您將能夠在物理系統運行後擷取結果。查詢的索引將在幀內被 生成 使用,因此它可以儲存於任何地方——也可儲存在可復原幀資料之外。

C#

namespace Quantum
{
    public unsafe struct ProjectileFilter
    {
        public EntityRef EntityRef;
        public Transform3D* Transform;
        public Projectile* Component;
    }

    public unsafe class ProjectileHitQueryInjectionSystem : SystemMainThread
    {
        public override void Update(Frame f)
        {
            var projectileFilter = f.Unsafe.FilterStruct<ProjectileFilter>();
            var projectile = default(ProjectileFilter);

            while (projectileFilter.Next(&projectile))
            {
                projectile.Component->PathQueryIndex = f.Physics3D.AddRaycastQuery(
                    projectile.Transform->Position,
                    projectile.Transform->Forward,
                    projectile.Component->Speed * f.DeltaTime);

                var spec = f.FindAsset<WeaponSpec>(projectile.Component->WeaponSpec.Id);

                projectile.Component->DamageZoneQueryIndex = f.Physics3D.AddOverlapShapeQuery(
                    projectile.Transform->Position,
                    projectile.Transform->Rotation,
                    spec.AttackShape.CreateShape(f),
                    spec.AttackLayers);
            }
        }
    }
}

重要事項: AddXXXQuery傳回的查詢索引,對於以後擷取結果而言絕對重要。因此建議儲存在附加到實體的元件中,且該實體是之後將需要處理命中的實體。

擷取查詢結果

可從任何在物理之後運行的系統來擷取查詢結果。為了擷取結果(命中集合*),您需要傳送先前儲存的索引到Frame.Physics.GetQueryHits()之中。

C#

using Photon.Deterministic;

namespace Quantum
{
    public unsafe class ProjectileHitRetrievalSystem : SystemMainThread
    {
        public override void Update(Frame f)
        {
            var projectileFilter = f.Unsafe.FilterStruct<ProjectileFilter>();
            var projectile = default(ProjectileFilter);

            while (projectileFilter.Next(&projectile))
            {
                var hitsOnTrajectory = f.Physics3D.GetQueryHits(projectile.Component->PathQueryIndex);
                if (hitsOnTrajectory.Count <= FP._0)
                {
                    projectile.Transform->Position =
                        projectile.Transform->Rotation *
                        projectile.Transform->Forward *
                        projectile.Component->Speed * f.DeltaTime;
                    continue;
                }

                var damageZoneHits = f.Physics3D.GetQueryHits(projectile.Component->DamageZoneQueryIndex);

                for (int i = 0; i < damageZoneHits.Count; i++)
                {
                    // Apply damage logic
                }
            }
        }
    }
}

除此之外,您可以透過public bool GetAllQueriesHits(out HitCollection* queriesHits, out int queriesCount)調用來取得所有廣相位結果,該調用也可以透過Frame.Physics進行。

注意事項

當使用廣相位查詢時,有一些需要謹記在心的重要事項:

  • 針對大數量(例如導彈),效能提升大約20倍。
  • 它們基於物理系統啟動之前的幀狀態。
  • 廣相位查詢不在幀之間進行;換句話說,它們需要在物理之前,在幀開始時被插入。在物理已經運行之後插入的廣相位查詢,將永不傳回一個結果。這是因為Quantum的物理是無狀態的。

模擬CCD

Quantum的物理是無狀態的。持續碰撞偵測在這樣的系統中將非常耗費資源。在無狀態物理引擎中模擬CCD行為的解決方案一般涉及延展到一個幀的預期移動的射線投射或形狀重疊。

這個主題通常與快速移動的實體(例如導彈)結合在一起。根據您的快速移動的物件的大小,我們建議使用以下方法之一:

  • 在移動方向的一個短射線,其長度為velocity * deltaTime;或,
  • 一個單一重疊;請注意一個形狀重疊也可以透過複合形狀完成。

這些解決方案都可以複製100%準確的CCD,從而獲得更好的總體效能。為了進一步提高效能,您可以將其與廣相位查詢相結合。

Back to top