Exemplo n.º 1
0
        private static void CreateConstraint(PhysicsWorld world, float3 up,
                                             int hitRigidBodyIndex, ColliderKey hitColliderKey, float3 hitPosition, float3 hitSurfaceNormal,
                                             float hitDistance,
                                             float skinWidth, float maxSlopeCos, ref NativeList <SurfaceConstraintInfo> constraints)
        {
            CreateConstraintFromHit(world, hitRigidBodyIndex, hitColliderKey, hitPosition,
                                    hitSurfaceNormal, hitDistance, skinWidth, out var constraint);

            // Check if max slope plane is required
            var verticalComponent = math.dot(constraint.Plane.Normal, up);
            var shouldAddPlane    = verticalComponent > KSimplexSolverEpsilon && verticalComponent < maxSlopeCos;

            if (shouldAddPlane)
            {
                constraint.IsTooSteep = true;
                CreateMaxSlopeConstraint(up, ref constraint, out var maxSlopeConstraint);
                constraints.Add(maxSlopeConstraint);
            }

            // Prepare velocity to resolve penetration
            ResolveConstraintPenetration(ref constraint);

            // Add original constraint to the list
            constraints.Add(constraint);
        }
        private static bool IsTransparent(BlobAssetReference <Collider> collider, ColliderKey key)
        {
            bool bIsTransparent = false;

            unsafe
            {
                // Only Convex Colliders have Materials associated with them. So base on CollisionType
                // we'll need to cast from the base Collider type, hence, we need the pointer.
                var c = (Collider *)collider.GetUnsafePtr();
                {
                    var cc = ((ConvexCollider *)c);

                    // We also need to check if our Collider is Composite (i.e. has children).
                    // If it is then we grab the actual leaf node hit by the ray.
                    // Checking if our collider is composite
                    if (c->CollisionType != CollisionType.Convex)
                    {
                        // If it is, get the leaf as a Convex Collider
                        c->GetLeaf(key, out ChildCollider child);
                        cc = (ConvexCollider *)child.Collider;
                    }

                    // Now we've definitely got a ConvexCollider so can check the Material.
                    bIsTransparent = (cc->Material.CustomTags & k_TransparentCustomTag) != 0;
                }
            }

            return(bIsTransparent);
        }
Exemplo n.º 3
0
        private static unsafe void ConvexComposite(
            Context context, ColliderKey convexKeyA,
            Collider *convexColliderA, Collider *compositeColliderB, MTransform worldFromA, MTransform worldFromB,
            MotionExpansion expansion, bool flipped, ref BlockStream.Writer contactWriter)
        {
            // Calculate AABB of A in B
            MTransform bFromWorld = Inverse(worldFromB);
            MTransform bFromA     = Mul(bFromWorld, worldFromA);
            var        transform  = new RigidTransform(new quaternion(bFromA.Rotation), bFromA.Translation); // TODO: avoid this conversion to and back from float3x3
            Aabb       aabbAinB   = expansion.ExpandAabb(convexColliderA->CalculateAabb(transform));

            // Do the midphase query and build manifolds for any overlapping leaf colliders
            var input = new OverlapAabbInput {
                Aabb = aabbAinB, Filter = convexColliderA->Filter
            };
            var collector = new ConvexCompositeOverlapCollector(
                context,
                convexColliderA, convexKeyA, compositeColliderB,
                worldFromA, worldFromB, expansion.MaxDistance, flipped,
                contactWriter);

            OverlapQueries.AabbCollider(input, compositeColliderB, ref collector);

            // Keep updated writer state
            contactWriter = collector.m_ContactWriter;
        }
Exemplo n.º 4
0
    private ColliderGroup CreateColliderGroup(ColliderGrid grid, ColliderCell cell, ColliderKey key)
    {
        ColliderGroup colliderGroup = Facepunch.Pool.Get <ColliderGroup>();

        colliderGroup.Initialize(grid, cell, key);
        return(colliderGroup);
    }
Exemplo n.º 5
0
            public void AddLeaf(ColliderKey key, ref ChildCollider leaf)
            {
                MTransform worldFromLeafA = Mul(m_WorldFromA, new MTransform(leaf.TransformFromChild));

                ConvexComposite(
                    m_Context, m_KeyPath.GetLeafKey(key), leaf.Collider, m_CompositeColliderB,
                    worldFromLeafA, m_WorldFromB, m_Expansion, m_Flipped);
            }
 public void TransformNewHits(int oldNumHits, float oldFraction, Math.MTransform transform, uint numSubKeyBits, uint subKey)
 {
     m_lastColliderKey = ColliderKey.Empty;
     m_lastColliderKey.PushSubKey(numSubKeyBits, subKey);
     if (m_ClosestHit.Fraction < oldFraction)
     {
         m_ClosestHit.Transform(transform, numSubKeyBits, subKey);
     }
 }
Exemplo n.º 7
0
    private ColliderGroup CreateColliderGroup(
        ColliderGrid grid,
        ColliderCell cell,
        ColliderKey key)
    {
        M0 m0 = Pool.Get <ColliderGroup>();

        ((ColliderGroup)m0).Initialize(grid, cell, key);
        return((ColliderGroup)m0);
    }
Exemplo n.º 8
0
        public ColliderKey SetSubKey(uint childSubKeyNumOfBits, uint childSubKey)
        {
            var parentColliderKey = ColliderKey;

            parentColliderKey.PopSubKey(NumColliderKeyBits, out uint parentKey);

            var colliderKey = new ColliderKey(childSubKeyNumOfBits, childSubKey);

            colliderKey.PushSubKey(NumColliderKeyBits, parentKey);
            return(colliderKey);
        }
 private void FallbackToPreviousHit()
 {
     MaxFraction       = m_prevMaxFraction;
     m_prevMaxFraction = 0;
     m_ClosestHit      = m_OldHit;
     m_OldHit          = default;
     m_lastColliderKey = m_prevColliderKey;
     m_prevColliderKey = ColliderKey.Empty;
     NumHits           = m_prevNumHits;
     m_prevNumHits     = 0;
 }
Exemplo n.º 10
0
        public QueryContext(int physicsBodyIndex, Entity entity, PhysicsTransform localToWorldTransform)
        {
            PhysicsBodyIndex      = physicsBodyIndex;
            Entity                = entity;
            LocalToWorldTransform = localToWorldTransform;

            ColliderKey        = ColliderKey.Empty;
            NumColliderKeyBits = 0;

            m_IsInitialized = 1;
        }
Exemplo n.º 11
0
    public ColliderGroup FindBatchGroup(ColliderBatch collider)
    {
        ColliderKey   key = new ColliderKey(collider);
        ColliderGroup colliderGroup;

        if (!this.batches.TryGetValue(key, ref colliderGroup))
        {
            colliderGroup = this.CreateColliderGroup(this.grid, this, key);
            this.batches.Add(key, colliderGroup);
        }
        return(colliderGroup);
    }
 public bool AddHit(T hit)
 {
     Assert.IsTrue(hit.Fraction <= MaxFraction);
     m_prevMaxFraction = MaxFraction;
     MaxFraction       = hit.Fraction;
     m_OldHit          = m_ClosestHit;
     m_ClosestHit      = hit;
     m_prevNumHits     = NumHits;
     NumHits           = 1;
     m_prevColliderKey = m_lastColliderKey;
     m_lastColliderKey = ColliderKey.Empty;
     return(true);
 }
 public SelfAndTriggerFilteringClosestHitCollector(PhysicsWorld world, int rbIndex, float maxFraction)
 {
     m_prevMaxFraction = 0;
     MaxFraction       = maxFraction;
     m_OldHit          = default;
     m_ClosestHit      = default;
     m_prevNumHits     = 0;
     NumHits           = 0;
     m_selfRBIndex     = rbIndex;
     m_world           = world;
     m_lastColliderKey = ColliderKey.Empty;
     m_prevColliderKey = ColliderKey.Empty;
 }
Exemplo n.º 14
0
 /// <summary>
 /// Given the root Collider of a hierarchy and a ColliderKey referencing a child in that hierarchy,
 /// this function returns the ChildCollider requested.
 /// </summary>
 /// <param name="rootColliderPtr">A <see cref="Collider"/> at the root of a Collider hierarchy.</param>
 /// <param name="childColliderKey">A <see cref="ColliderKey"/> referencing a child Collider somewhere in the hierarchy below rootColliderPtr.</param>
 /// <param name="childCollider">A valid <see cref="ChildCollider"/> returned from the hierarchy, if found.</param>
 /// <returns>Whether a specified ColliderKey was successfully found in the hierarchy.</returns>
 public static unsafe bool TryGetChildInHierarchy(Collider *rootColliderPtr, ColliderKey childColliderKey, out ChildCollider childCollider)
 {
     //public static unsafe bool GetLeafCollider(Collider* root, RigidTransform rootTransform, ColliderKey key, out ChildCollider leaf)
     childCollider = new ChildCollider(rootColliderPtr, RigidTransform.identity);
     while (!childColliderKey.Equals(ColliderKey.Empty))
     {
         if (!childCollider.Collider->GetChild(ref childColliderKey, out ChildCollider child))
         {
             break;
         }
         childCollider = new ChildCollider(childCollider, child);
     }
     return(childCollider.Collider != null);
 }
Exemplo n.º 15
0
 public ConvexCompositeOverlapCollector(
     Context context,
     Collider *convexCollider, ColliderKey convexColliderKey, Collider *compositeCollider,
     MTransform worldFromA, MTransform worldFromB, float collisionTolerance, bool flipped)
 {
     m_Context                  = context;
     m_ConvexColliderA          = convexCollider;
     m_ConvexColliderKey        = convexColliderKey;
     m_CompositeColliderB       = compositeCollider;
     m_CompositeColliderKeyPath = ColliderKeyPath.Empty;
     m_WorldFromA               = worldFromA;
     m_WorldFromB               = worldFromB;
     m_CollisionTolerance       = collisionTolerance;
     m_Flipped                  = flipped;
 }
Exemplo n.º 16
0
 private static SurfaceConstraintInfo CreateConstraint(
     ColliderKey colliderKey, float3 hitPosition, float3 normal, float distance,
     int priority, int rigidBodyIndex, bool touched, float3 velocity)
 {
     return(new SurfaceConstraintInfo
     {
         ColliderKey = colliderKey,
         HitPosition = hitPosition,
         Plane = new Plane(normal, distance),
         Priority = priority,
         RigidBodyIndex = rigidBodyIndex,
         Touched = touched,
         Velocity = velocity
     });
 }
Exemplo n.º 17
0
 public void EnterPool()
 {
     this.Invalidated  = false;
     this.NeedsRefresh = false;
     this.Processing   = false;
     this.Preserving   = false;
     this.Colliders.Clear();
     this.TempColliders.Clear();
     this.Batches.Clear();
     this.TempBatches.Clear();
     this.TempInstances.Clear();
     this.grid = null;
     this.cell = null;
     this.key  = new ColliderKey();
 }
Exemplo n.º 18
0
 public bool GetChild(ref ColliderKey key, out ChildCollider child)
 {
     if (key.PopSubKey(NumColliderKeyBits, out uint subKey))
     {
         var index    = new int2(((int)subKey >> 1) & ((1 << (int)Terrain.NumXBits) - 1), (int)subKey >> ((int)Terrain.NumXBits + 1));
         int triangle = (int)subKey & 1;
         child = Terrain.GetTriangle(index, triangle, Filter, Material);
         return(true);
     }
     else
     {
         child = new ChildCollider();
         return(false);
     }
 }
Exemplo n.º 19
0
        /// <summary>
        /// Given the root Collider of a hierarchy and a ColliderKey referencing a child in that hierarchy,
        /// this function returns the ColliderKey referencing the parent Collider.
        /// </summary>
        /// <param name="rootColliderPtr">A <see cref="Collider"/> at the root of a Collider hierarchy.</param>
        /// <param name="childColliderKey">A <see cref="ColliderKey"/> referencing a child Collider somewhere in the hierarchy below rootColliderPtr.</param>
        /// <param name="parentColliderKey">A <see cref="ColliderKey"/> referencing the parent of the child Collider. Will be ColliderKey.Empty if the parameters where invalid.</param>
        /// <returns>Whether the parent was successfully found in the hierarchy.</returns>
        public static unsafe bool TryGetParentColliderKey(Collider *rootColliderPtr, ColliderKey childColliderKey, out ColliderKey parentColliderKey)
        {
            var childColliderPtr        = rootColliderPtr;
            var childColliderKeyNumBits = childColliderPtr->NumColliderKeyBits;

            // Start with an Empty collider key and push sub keys onto it as we traverse down the compound hierarchy.
            var parentColliderKeyPath = ColliderKeyPath.Empty;

            // On the way down, the childColliderKey pops of sub keys and pushes them onto the parentColliderKeyPath
            do
            {
                childColliderKey.PopSubKey(childColliderKeyNumBits, out var childIndex);
                switch (childColliderPtr->Type)
                {
                case ColliderType.Compound:
                    // Get the next child down and loop again
                    parentColliderKeyPath.PushChildKey(new ColliderKeyPath(new ColliderKey(childColliderKeyNumBits, childIndex), childColliderKeyNumBits));
                    childColliderPtr        = ((CompoundCollider *)childColliderPtr)->Children[(int)childIndex].Collider;
                    childColliderKeyNumBits = childColliderPtr->NumColliderKeyBits;
                    break;

                case ColliderType.Mesh:
                case ColliderType.Terrain:
                    // We've hit a Terrain or Mesh collider so there should only be PolygonColliders below this.
                    // At this point the childColliderKey should be Empty and childIndex should be the index of the polygon.
                    if (!childColliderKey.Equals(ColliderKey.Empty))
                    {
                        // We've reached the bottom without popping all the child keys.
                        // The given childColliderKey doesn't fit this hierarchy!
                        parentColliderKey = ColliderKey.Empty;
                        return(false);
                    }
                    break;

                default:
                    // We've hit a Convex collider, so rootColliderPtr must not have been
                    // the root of a hierarchy in the first place and so there is no parent!
                    parentColliderKey = ColliderKey.Empty;
                    return(false);
                }
            }while (!childColliderKey.Equals(ColliderKey.Empty) &&
                    !childColliderPtr->CollisionType.Equals(CollisionType.Convex));

            parentColliderKey = parentColliderKeyPath.Key;
            // childColliderKey should be Empty at this point.
            // However, if it isn't then we reached a leaf without finding the child collider!
            return(childColliderKey.Equals(ColliderKey.Empty));
        }
        public static unsafe bool IsTrigger(Collider *c, ColliderKey key)
        {
            bool bIsTrigger = false;

            {
                var cc = ((ConvexCollider *)c);
                if (cc->CollisionType != CollisionType.Convex)
                {
                    c->GetLeaf(key, out ChildCollider child);
                    cc = (ConvexCollider *)child.Collider;
                    UnityEngine.Assertions.Assert.IsTrue(cc->CollisionType == CollisionType.Convex);
                }
                bIsTrigger = cc->Material.IsTrigger;
            }
            return(bIsTrigger);
        }
Exemplo n.º 21
0
 public void GetLeaves <T>(ref T collector) where T : struct, ILeafColliderCollector
 {
     for (int x = 0; x < Terrain.Size.x - 1; x++)
     {
         for (int y = 0; y < Terrain.Size.y - 1; y++)
         {
             var index = new int2(x, y);
             for (int iTriangle = 0; iTriangle < 2; iTriangle++)
             {
                 ColliderKey   key  = Terrain.GetColliderKey(index, iTriangle);
                 ChildCollider leaf = Terrain.GetTriangle(index, iTriangle, Filter, Material);
                 collector.AddLeaf(key, ref leaf);
             }
         }
     }
 }
Exemplo n.º 22
0
        public static unsafe bool IsTrigger(BlobAssetReference <Collider> collider, ColliderKey key)
        {
            bool bIsTrigger = false;
            var  c          = (Collider *)collider.GetUnsafePtr();

            {
                var cc = ((ConvexCollider *)c);
                if (cc->CollisionType != CollisionType.Convex)
                {
                    c->GetLeaf(key, out ChildCollider child);
                    cc = (ConvexCollider *)child.Collider;
                    Assert.IsTrue(cc->CollisionType == CollisionType.Convex);
                }
                bIsTrigger = cc->Material.IsTrigger;
            }
            return(bIsTrigger);
        }
Exemplo n.º 23
0
            public void AabbLeaf <T>(OverlapAabbInput input, int primitiveKey, [NoAlias] ref T collector) where T : struct, IOverlapCollector
            {
                fixed(uint *keys = m_Keys)
                {
                    keys[m_NumKeys++] = new ColliderKey(m_NumColliderKeyBits, (uint)(primitiveKey << 1)).Value;

                    Mesh.PrimitiveFlags flags = m_Mesh->GetPrimitiveFlags(primitiveKey);
                    if (Mesh.IsPrimitiveFlagSet(flags, Mesh.PrimitiveFlags.IsTrianglePair) &&
                        !Mesh.IsPrimitiveFlagSet(flags, Mesh.PrimitiveFlags.IsQuad))
                    {
                        keys[m_NumKeys++] = new ColliderKey(m_NumColliderKeyBits, (uint)(primitiveKey << 1) | 1).Value;
                    }
                }

                if (m_NumKeys > k_MaxKeys - 8)
                {
                    Flush(ref collector);
                }
            }
Exemplo n.º 24
0
 public StatefulTriggerEvent(Entity entityA, Entity entityB, int bodyIndexA, int bodyIndexB,
                             ColliderKey colliderKeyA, ColliderKey colliderKeyB)
 {
     Entities = new EntityPair
     {
         EntityA = entityA,
         EntityB = entityB
     };
     BodyIndices = new BodyIndexPair
     {
         BodyIndexA = bodyIndexA,
         BodyIndexB = bodyIndexB
     };
     ColliderKeys = new ColliderKeyPair
     {
         ColliderKeyA = colliderKeyA,
         ColliderKeyB = colliderKeyB
     };
     State = default;
 }
 public StatefulCollisionEvent(Entity entityA, Entity entityB, int bodyIndexA, int bodyIndexB,
                               ColliderKey colliderKeyA, ColliderKey colliderKeyB, float3 normal)
 {
     Entities = new EntityPair
     {
         EntityA = entityA,
         EntityB = entityB
     };
     BodyIndices = new BodyIndexPair
     {
         BodyIndexA = bodyIndexA,
         BodyIndexB = bodyIndexB
     };
     ColliderKeys = new ColliderKeyPair
     {
         ColliderKeyA = colliderKeyA,
         ColliderKeyB = colliderKeyB
     };
     Normal           = normal;
     CollidingState   = default;
     CollisionDetails = default;
 }
Exemplo n.º 26
0
        public static void CreateConstraintFromHit(PhysicsWorld world, ColliderKey key, int rigidbodyIndex, float3 position, float3 velocity, float3 normal, float distance, float deltaTime, out SurfaceConstraintInfo constraint)
        {
            bool dynamicBody = 0 <= rigidbodyIndex && rigidbodyIndex < world.NumDynamicBodies;

            constraint = new SurfaceConstraintInfo
            {
                Plane = new Plane
                {
                    Normal   = normal,
                    Distance = distance
                },
                RigidBodyIndex = rigidbodyIndex,
                ColliderKey    = key,
                HitPosition    = position,
                Velocity       = dynamicBody ? world.MotionVelocities[rigidbodyIndex].LinearVelocity : velocity
            };

            if (distance < 0.0f)
            {
                constraint.Velocity = constraint.Velocity - constraint.Plane.Normal * distance;
            }
        }
    private static void CreateConstraint(PhysicsWorld world, float3 up,
                                         int hitRigidBodyIndex, ColliderKey hitColliderKey, float3 hitPosition, float3 hitSurfaceNormal, float hitDistance,
                                         float skinWidth, float maxSlopeCos, ref NativeArray <SurfaceConstraintInfo> constraints, ref int numConstraints)
    {
        CreateConstraintFromHit(world, hitRigidBodyIndex, hitColliderKey, hitPosition,
                                hitSurfaceNormal, hitDistance, skinWidth, out SurfaceConstraintInfo constraint);

        // Check if max slope plane is required
        float verticalComponent = math.dot(constraint.Plane.Normal, up);
        bool  shouldAddPlane    = verticalComponent > k_SimplexSolverEpsilon && verticalComponent < maxSlopeCos;

        if (shouldAddPlane)
        {
            AddMaxSlopeConstraint(up, ref constraint, ref constraints, ref numConstraints);
        }

        // Prepare velocity to resolve penetration
        ResolveConstraintPenetration(ref constraint);

        // Add original constraint to the list
        constraints[numConstraints++] = constraint;
    }
Exemplo n.º 28
0
    private static void CreateConstraintFromHit(PhysicsWorld world, float3 gravity, float deltaTime, int rigidBodyIndex, ColliderKey colliderKey,
                                                float3 hitPosition, float3 normal, float distance, bool zeroVelocity, out SurfaceConstraintInfo constraint)
    {
        bool bodyIsDynamic = 0 <= rigidBodyIndex && rigidBodyIndex < world.NumDynamicBodies;

        constraint = new SurfaceConstraintInfo()
        {
            Plane = new Plane
            {
                Normal   = normal,
                Distance = distance,
            },
            RigidBodyIndex = rigidBodyIndex,
            ColliderKey    = colliderKey,
            HitPosition    = hitPosition,
            Velocity       = bodyIsDynamic && !zeroVelocity ?
                             world.MotionVelocities[rigidBodyIndex].LinearVelocity - world.MotionDatas[rigidBodyIndex].GravityFactor * gravity * deltaTime :
                             constraint.Velocity = float3.zero,
            Priority = bodyIsDynamic ? 1 : 0
        };

        // Fix up the velocity to enable penetration recovery
        if (distance < 0.0f)
        {
            float3 newVel = constraint.Velocity - constraint.Plane.Normal * distance;
            constraint.Velocity = newVel;
        }
    }
Exemplo n.º 29
0
    private static void CreateConstraintFromHit(PhysicsWorld world, int rigidBodyIndex, ColliderKey colliderKey,
                                                float3 hitPosition, float3 normal, float distance, float skinWidth, out SurfaceConstraintInfo constraint)
    {
        bool bodyIsDynamic = 0 <= rigidBodyIndex && rigidBodyIndex < world.NumDynamicBodies;

        constraint = new SurfaceConstraintInfo()
        {
            Plane = new Unity.Physics.Plane
            {
                Normal   = normal,
                Distance = distance - skinWidth,
            },
            RigidBodyIndex = rigidBodyIndex,
            ColliderKey    = colliderKey,
            HitPosition    = hitPosition,
            Velocity       = bodyIsDynamic ?
                             world.GetLinearVelocity(rigidBodyIndex, hitPosition) :
                             float3.zero,
            Priority = bodyIsDynamic ? 1 : 0
        };
    }
Exemplo n.º 30
0
 public bool GetLeaf(ColliderKey key, out ChildCollider leaf)
 {
     return(GetChild(ref key, out leaf)); // all children of TerrainCollider are leaves
 }
Exemplo n.º 31
0
  private Collider2D CreateCollider( int scriptId, ColliderKey key )
  {
    Collider2D newCollider = null;

    //  Using bounding box shape as collider.
    if ( key.colliderShape == ColliderShape.eBox )
    {
      //  Update collider bounding box if available.
      float[] box = new float[4];
      if ( Internal.CalculateBoundingBox( scriptId, box ) )
      {
        BoxCollider2D boxCollider = gameObject.AddComponent<BoxCollider2D>();
        boxCollider.enabled = true;
        boxCollider.isTrigger = colliderTrigger;

#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
        boxCollider.center = new Vector2( (box[0]+box[2]) * 0.5f, (box[1]+box[3]) * 0.5f );
#else // UNITY_5_0
        boxCollider.offset = new Vector2( (box[0]+box[2]) * 0.5f, (box[1]+box[3]) * 0.5f );
#endif
        boxCollider.size = new Vector2( box[2]-box[0], box[3]-box[1] );

        colliderKeys.Add( key.ToString() );
        colliderLinks.Add( boxCollider );

        newCollider = boxCollider;
      }
    }
    //  Calculate convex hull shape as collider.
    else if ( colliderShape == ColliderShape.eConvexHull )
    {
      IntPtr convexHullArrayRaw  = IntPtr.Zero;
      int    convexHullSize      = 0;

      if ( Internal.CalculateConvexHull( scriptId, ref convexHullArrayRaw, ref convexHullSize ) )
      {
        float[] convexHullArray = new float[ convexHullSize * 2 ];
        Marshal.Copy( convexHullArrayRaw,
            convexHullArray,
            0,
            convexHullSize * 2 );

        Internal.DeallocateConvexHull( convexHullArrayRaw );

        PolygonCollider2D polygonCollider = gameObject.AddComponent<PolygonCollider2D>();
        polygonCollider.enabled = true;
        polygonCollider.isTrigger = colliderTrigger;
        polygonCollider.pathCount = 1;

        Vector2[] path = new Vector2[ convexHullSize ];
        for( int idx=0 ; idx < convexHullSize ; ++idx )
        {
          path[idx] = new Vector2( convexHullArray[idx*2], convexHullArray[idx*2 + 1] );
        }

        polygonCollider.SetPath( 0, path );

        colliderKeys.Add( key.ToString() );
        colliderLinks.Add( polygonCollider );

        newCollider = polygonCollider;
      }
    }
    //  Calculate tight polygons as collider.
    else // if ( colliderShape == ColliderShape.ePolygons )
    {
      IntPtr polygonArrayRaw     = IntPtr.Zero;
      int    polygonSize         = 0;

      IntPtr subPolygonArrayRaw  = IntPtr.Zero;
      int    subPolygonSize      = 0;

      if ( Internal.CalculatePolygons( scriptId, ref polygonArrayRaw, ref polygonSize, ref subPolygonArrayRaw, ref subPolygonSize ) )
      {
        float[] polygonArray = new float[ polygonSize * 2 ];
        Marshal.Copy( polygonArrayRaw,
            polygonArray,
            0,
            polygonSize * 2 );

        int[] subPolygonArray = new int[ subPolygonSize ];
        Marshal.Copy( subPolygonArrayRaw,
            subPolygonArray,
            0,
            subPolygonSize );

        Internal.DeallocatePolygons( polygonArrayRaw, subPolygonArrayRaw );

        PolygonCollider2D polygonCollider = gameObject.AddComponent<PolygonCollider2D>();
        polygonCollider.enabled = true;
        polygonCollider.isTrigger = colliderTrigger;
        polygonCollider.pathCount = subPolygonSize;

        int baseIndex = 0;
        for ( int polygonIndex=0 ; polygonIndex < subPolygonSize ; ++polygonIndex )
        {
          int numberOfPoints = subPolygonArray[polygonIndex];
          int lastIndex = baseIndex + numberOfPoints;

          Vector2[] path = new Vector2[numberOfPoints];
          for ( int idx=0 ; idx<numberOfPoints ; ++idx )
          {
            int ptIndex = baseIndex + idx;
            path[idx] = new Vector2( polygonArray[ptIndex*2], polygonArray[ptIndex*2 + 1] );
          }

          polygonCollider.SetPath(polygonIndex, path);

          baseIndex = lastIndex;
        }

        colliderKeys.Add( key.ToString() );
        colliderLinks.Add( polygonCollider );

        newCollider = polygonCollider;
      }
    }

    return newCollider;
  }