Advertisement
bero1985

Convex convex SAT

May 14th, 2015
1,080
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 23.43 KB | None | 0 0
  1.  procedure CollideConvexHullWithConvexHull(ShapeA,ShapeB:TEnginePhysicsShapeConvexHull);
  2.  const kTolerance=0.005; // Skip near parallel edges: |Ea x Eb| = sin(alpha) * |Ea| * |Eb|
  3.   function IsMinkowskiFace(const A,B,B_x_A,C,D,D_x_C:TVector3):boolean;
  4.   var CBA,DBA,ADC,BDC:single;  
  5.   begin
  6.    // Test if arcs AB and CD intersect on the unit sphere
  7.    CBA:=Vector3Dot(C,B_x_A);
  8.    DBA:=Vector3Dot(D,B_x_A);
  9.    ADC:=Vector3Dot(A,D_x_C);
  10.    BDC:=Vector3Dot(B,D_x_C);
  11.    result:=((CBA*DBA<0.0)) and ((ADC*BDC)<0.0) and ((CBA*BDC)>0.0);
  12.   end;
  13.   function TestEarlyFaceDirection(const HullA,HullB:TEnginePhysicsShapeConvexHull;var FaceQuery:TEnginePhysicsContactFaceQuery):boolean;
  14.   var Plane:TPlane;
  15.       Transform:TMatrix4x4;
  16.   begin
  17.    Transform:=Matrix4x4TermMul(HullA.WorldTransform,HullB.InverseWorldTransform);
  18.    Plane:=PlaneFastTransform(HullA.ConvexHull.Faces[FaceQuery.Index].Plane,Transform);
  19.    FaceQuery.Separation:=PlaneVectorDistance(Plane,HullB.GetLocalSupport(Vector3Neg(Plane.Normal)));
  20.    result:=FaceQuery.Separation>0.0;
  21.   end;
  22.   function TestEarlyEdgeDirection(const HullA,HullB:TEnginePhysicsShapeConvexHull;var EdgeQuery:TEnginePhysicsContactEdgeQuery):boolean;
  23.   var EdgeA,EdgeB:PEnginePhysicsConvexHullEdge;
  24.       L:single;
  25.       CenterA,Pa,Qa,Ea,Ua,Va,Pb,Qb,Eb,Ub,Vb,Ea_x_Eb,Normal:TVector3;
  26.       Transform:TMatrix4x4;
  27.   begin
  28.    result:=false;
  29.    Transform:=Matrix4x4TermMul(HullA.WorldTransform,HullB.InverseWorldTransform);
  30.    CenterA:=HullA.GetCenter(Transform);
  31.    EdgeA:=@HullA.ConvexHull.Edges[EdgeQuery.IndexA];
  32.    Pa:=Vector3TermMatrixMul(HullA.ConvexHull.Vertices[EdgeA^.Vertices[0]].Position,Transform);
  33.    Qa:=Vector3TermMatrixMul(HullA.ConvexHull.Vertices[EdgeA^.Vertices[1]].Position,Transform);
  34.    Ea:=Vector3Sub(Qa,Pa);
  35.    Ua:=Vector3Norm(Vector3TermMatrixMulBasis(HullA.ConvexHull.Faces[EdgeA^.Faces[0]].Plane.Normal,Transform));
  36.    Va:=Vector3Norm(Vector3TermMatrixMulBasis(HullA.ConvexHull.Faces[EdgeA^.Faces[1]].Plane.Normal,Transform));
  37.    EdgeB:=@HullB.ConvexHull.Edges[EdgeQuery.IndexB];
  38.    Pb:=HullB.ConvexHull.Vertices[EdgeB^.Vertices[0]].Position;
  39.    Qb:=HullB.ConvexHull.Vertices[EdgeB^.Vertices[1]].Position;
  40.    Eb:=Vector3Sub(Qb,Pb);
  41.    Ub:=HullB.ConvexHull.Faces[EdgeB^.Faces[0]].Plane.Normal;
  42.    Vb:=HullB.ConvexHull.Faces[EdgeB^.Faces[1]].Plane.Normal;
  43.    if IsMinkowskiFace(Ua,Va,Vector3Neg(Ea),Vector3Neg(Ub),Vector3Neg(Vb),Vector3Neg(Eb)) then begin
  44.     // Build search direction
  45.     Ea_x_Eb:=Vector3Cross(Ea,Eb);
  46.  
  47.     // Skip near parallel edges: |Ea x Eb| = sin(alpha) * |Ea| * |Eb|
  48.     L:=Vector3Length(Ea_x_Eb);
  49.     if L<(sqrt(Vector3LengthSquared(Ea)*Vector3LengthSquared(Eb))*kTolerance) then begin
  50.      result:=false;
  51.      exit;
  52.     end;
  53.  
  54.     // Assure consistent normal orientation (here: HullA -> HullB)
  55.     Normal:=Vector3ScalarMul(Ea_x_Eb,1.0/L);
  56.     if Vector3Dot(Normal,Vector3Sub(Pa,CenterA))<0.0 then begin
  57.      Normal:=Vector3Neg(Normal);
  58.     end;
  59.  
  60.     // s = Dot(Normal, Pb) - d = Dot(Normal, Pb) - Dot(Normal, Pa) = Dot(Normal, Pb - Pa)
  61.     EdgeQuery.Separation:=Vector3Dot(Normal,Vector3Sub(Pb,Pa));
  62.     if EdgeQuery.Separation>0.0 then begin
  63.      result:=true;
  64.     end;
  65.  
  66.    end;
  67.   end;
  68.   procedure QueryFaceDirections(const HullA,HullB:TEnginePhysicsShapeConvexHull;out OutFaceQuery:TEnginePhysicsContactFaceQuery);
  69.   var MaxIndex,Index:longint;
  70.       MaxSeparation,Separation:single;
  71.       Plane:TPlane;
  72.       Transform:TMatrix4x4;
  73.   begin
  74.    Transform:=Matrix4x4TermMul(HullA.WorldTransform,HullB.InverseWorldTransform);
  75.    MaxIndex:=-1;
  76.    MaxSeparation:=-3.4e+38;
  77.    for Index:=0 to HullA.ConvexHull.CountFaces-1 do begin
  78.     Plane:=PlaneFastTransform(HullA.ConvexHull.Faces[Index].Plane,Transform);
  79.     Separation:=PlaneVectorDistance(Plane,HullB.GetLocalSupport(Vector3Neg(Plane.Normal)));
  80.     if (Index=0) or (MaxSeparation<Separation) then begin
  81.      MaxSeparation:=Separation;
  82.      MaxIndex:=Index;
  83.      if MaxSeparation>0.0 then begin
  84.       break;
  85.      end;
  86.     end;
  87.    end;
  88.    OutFaceQuery.Index:=MaxIndex;
  89.    OutFaceQuery.Separation:=MaxSeparation;
  90.   end;
  91.   procedure QueryEdgeDirections(const HullA,HullB:TEnginePhysicsShapeConvexHull;out OutEdgeQuery:TEnginePhysicsContactEdgeQuery);
  92.   var EdgeA,EdgeB:PEnginePhysicsConvexHullEdge;
  93.       IndexA,IndexB,MaxIndexA,MaxIndexB:longint;
  94.       MaxSeparation,Separation,L:single;
  95.       CenterA,Pa,Qa,Ea,Ua,Va,Pb,Qb,Eb,Ub,Vb,Ea_x_Eb,Normal:TVector3;
  96.       Transform:TMatrix4x4;
  97.       First:boolean;
  98.   begin
  99.    MaxIndexA:=-1;
  100.    MaxIndexB:=-1;
  101.    MaxSeparation:=-3.4e+38;
  102.    Transform:=Matrix4x4TermMul(HullA.WorldTransform,HullB.InverseWorldTransform);
  103.    CenterA:=HullA.GetCenter(Transform);
  104.    First:=true;
  105.    for IndexA:=0 to HullA.ConvexHull.CountEdges-1 do begin
  106.     EdgeA:=@HullA.ConvexHull.Edges[IndexA];
  107.     Pa:=Vector3TermMatrixMul(HullA.ConvexHull.Vertices[EdgeA^.Vertices[0]].Position,Transform);
  108.     Qa:=Vector3TermMatrixMul(HullA.ConvexHull.Vertices[EdgeA^.Vertices[1]].Position,Transform);
  109.     Ea:=Vector3Sub(Qa,Pa);
  110.     Ua:=Vector3Norm(Vector3TermMatrixMulBasis(HullA.ConvexHull.Faces[EdgeA^.Faces[0]].Plane.Normal,Transform));
  111.     Va:=Vector3Norm(Vector3TermMatrixMulBasis(HullA.ConvexHull.Faces[EdgeA^.Faces[1]].Plane.Normal,Transform));
  112.     for IndexB:=0 to HullB.ConvexHull.CountEdges-1 do begin
  113.      EdgeB:=@HullB.ConvexHull.Edges[IndexB];
  114.      Pb:=HullB.ConvexHull.Vertices[EdgeB^.Vertices[0]].Position;
  115.      Qb:=HullB.ConvexHull.Vertices[EdgeB^.Vertices[1]].Position;
  116.      Eb:=Vector3Sub(Qb,Pb);
  117.      Ub:=HullB.ConvexHull.Faces[EdgeB^.Faces[0]].Plane.Normal;
  118.      Vb:=HullB.ConvexHull.Faces[EdgeB^.Faces[1]].Plane.Normal;
  119.      if IsMinkowskiFace(Ua,Va,Vector3Neg(Ea),Vector3Neg(Ub),Vector3Neg(Vb),Vector3Neg(Eb)) then begin
  120.       // Build search direction
  121.       Ea_x_Eb:=Vector3Cross(Ea,Eb);
  122.  
  123.       // Skip near parallel edges: |Ea x Eb| = sin(alpha) * |Ea| * |Eb|
  124.       L:=Vector3Length(Ea_x_Eb);
  125.       if L<(sqrt(Vector3LengthSquared(Ea)*Vector3LengthSquared(Eb))*kTolerance) then begin
  126.        continue;
  127.       end;
  128.  
  129.       // Assure consistent normal orientation (here: HullA -> HullB)
  130.       Normal:=Vector3ScalarMul(Ea_x_Eb,1.0/L);
  131.       if Vector3Dot(Normal,Vector3Sub(Pa,CenterA))<0.0 then begin
  132.        Normal:=Vector3Neg(Normal);
  133.       end;
  134.  
  135.       // s = Dot(Normal, Pb) - d = Dot(Normal, Pb) - Dot(Normal, Pa) = Dot(Normal, Pb - Pa)
  136.       Separation:=Vector3Dot(Normal,Vector3Sub(Pb,Pa));
  137.       if First or (MaxSeparation<Separation) then begin
  138.        First:=false;
  139.        MaxSeparation:=Separation;
  140.        MaxIndexA:=IndexA;
  141.        MaxIndexB:=IndexB;
  142.        if MaxSeparation>0.0 then begin
  143.         break;
  144.        end;
  145.       end;
  146.  
  147.      end;
  148.     end;
  149.    end;
  150.    OutEdgeQuery.IndexA:=MaxIndexA;
  151.    OutEdgeQuery.IndexB:=MaxIndexB;
  152.    OutEdgeQuery.Separation:=MaxSeparation;
  153.   end;
  154.   function GetEdgeContact(var CA,CB,Normal:TVector3;const PA,QA,PB,QB,DirectionAB:TVector3):boolean;
  155.   var DA,DB,r:TVector3;
  156.       a,e,f,c,b,d,TA,TB:single;
  157.   begin
  158.    DA:=Vector3Sub(QA,PA);
  159.    DB:=Vector3Sub(QB,PB);
  160.    r:=Vector3Sub(PA,PB);
  161.      a:=Vector3LengthSquared(DA);
  162.      e:=Vector3LengthSquared(DB);
  163.      f:=Vector3Dot(DB,r);
  164.      c:=Vector3Dot(DA,r);
  165.    b:=Vector3Dot(DA,DB);
  166.    d:=(a*e)-sqr(b);
  167.    if (abs(d)>EPSILON) and (abs(e)>EPSILON) then begin
  168.  
  169.     TA:=((b*f)-(c*e))/d;
  170.     TB:=((b*TA)+f)/e;
  171.  
  172.     CA:=Vector3Add(PA,Vector3ScalarMul(DA,TA));
  173.     CB:=Vector3Add(PB,Vector3ScalarMul(DB,TB));
  174.  
  175.     Normal:=Vector3Norm(Vector3Cross(DA,DB));
  176.  
  177.     // Assure consistent normal orientation (here: HullA -> HullB)
  178.     if Vector3Dot(Normal,DirectionAB)<0.0 then begin
  179.      Normal:=Vector3Neg(Normal);
  180.     end;
  181.  
  182.     result:=true;
  183.  
  184.    end else begin
  185.     result:=false;
  186.    end;
  187.   end;
  188.   function FindIncidentFaceIndex(const ReferenceHull:TEnginePhysicsShapeConvexHull;const ReferenceFaceIndex:longint;const IncidentHull:TEnginePhysicsShapeConvexHull):longint;
  189.   var i:longint;
  190.       MinDot,Dot:single;
  191.       ReferenceNormal:TVector3;
  192.   begin
  193.    ReferenceNormal:=Vector3TermMatrixMulBasis(Vector3TermMatrixMulBasis(ReferenceHull.ConvexHull.Faces[ReferenceFaceIndex].Plane.Normal,
  194.                                                                         ReferenceHull.WorldTransform),
  195.                                               IncidentHull.InverseWorldTransform);
  196.    result:=-1;
  197.    MinDot:=3.4e+38;
  198.    for i:=0 to IncidentHull.ConvexHull.CountFaces-1 do begin
  199.     Dot:=Vector3Dot(ReferenceNormal,IncidentHull.ConvexHull.Faces[i].Plane.Normal);
  200.         if MinDot>Dot then begin
  201.          MinDot:=Dot;
  202.      result:=i;
  203.     end;
  204.    end;
  205.   end;
  206.   procedure ClipFaceContactPoints(const ReferenceHull:TEnginePhysicsShapeConvexHull;const ReferenceFaceIndex:longint;const IncidentHull:TEnginePhysicsShapeConvexHull;const IncidentFaceIndex:longint);
  207.   var Contact:PEnginePhysicsContact;
  208.       ReferenceVertexIndex,OtherReferenceVertexIndex,IncidentVertexIndex,ClipVertexIndex:longint;
  209.       ReferenceFace,IncidentFace:PEnginePhysicsConvexHullFace;
  210.       ClipVertex,FirstClipVertex,EndClipVertex:PVector3;
  211.       StartDistance,EndDistance,Distance:single;
  212.       ClipVertices:array[0..2] of TEnginePhysicsConvexHullVertexList;
  213.       ReferencePoint:TVector3;
  214.       ReferenceWorldPlane,ReferenceEdgePlane:TPlane;
  215.   begin
  216.  
  217.    ContactManager.CountTemporaryContacts[ThreadIndex]:=0;
  218.  
  219.    ReferenceFace:=@ReferenceHull.ConvexHull.Faces[ReferenceFaceIndex];
  220.    ReferenceWorldPlane:=PlaneFastTransform(ReferenceFace^.Plane,ReferenceHull.WorldTransform);
  221.  
  222.    IncidentFace:=@IncidentHull.ConvexHull.Faces[IncidentFaceIndex];
  223.  
  224.    ClipVertices[0]:=ContactManager.ConvexHullVertexLists[ThreadIndex,0];
  225.    ClipVertices[0].Clear;
  226.  
  227.    for IncidentVertexIndex:=0 to IncidentFace^.CountVertices-1 do begin
  228.     ClipVertices[0].Add(Vector3TermMatrixMul(IncidentHull.ConvexHull.Vertices[IncidentFace^.Vertices[IncidentVertexIndex]].Position,IncidentHull.WorldTransform));
  229.    end;
  230.  
  231.    ClipVertices[1]:=ContactManager.ConvexHullVertexLists[ThreadIndex,1];
  232.    ClipVertices[1].Clear;
  233.  
  234.    OtherReferenceVertexIndex:=ReferenceFace^.CountVertices-1;
  235.    for ReferenceVertexIndex:=0 to ReferenceFace^.CountVertices-1 do begin
  236.     if ClipVertices[0].Count>=2 then begin
  237.      ReferencePoint:=Vector3TermMatrixMul(ReferenceHull.ConvexHull.Vertices[ReferenceFace^.Vertices[ReferenceVertexIndex]].Position,ReferenceHull.WorldTransform);
  238.      ReferenceEdgePlane.Normal:=Vector3Neg(Vector3Norm(Vector3Cross(ReferenceWorldPlane.Normal,Vector3Sub(ReferencePoint,Vector3TermMatrixMul(ReferenceHull.ConvexHull.Vertices[ReferenceFace^.Vertices[OtherReferenceVertexIndex]].Position,ReferenceHull.WorldTransform)))));
  239.      ReferenceEdgePlane.Distance:=-Vector3Dot(ReferenceEdgePlane.Normal,ReferencePoint);
  240.      FirstClipVertex:=@ClipVertices[0].Vertices[ClipVertices[0].Count-1];
  241.      EndClipVertex:=@ClipVertices[0].Vertices[0];
  242.      StartDistance:=PlaneVectorDistance(ReferenceEdgePlane,FirstClipVertex^);
  243.      for ClipVertexIndex:=0 to ClipVertices[0].Count-1 do begin
  244.       EndClipVertex:=@ClipVertices[0].Vertices[ClipVertexIndex];
  245.       EndDistance:=PlaneVectorDistance(ReferenceEdgePlane,EndClipVertex^);
  246.       if StartDistance<0.0 then begin
  247.        if EndDistance<0.0 then begin
  248.         ClipVertices[1].Add(EndClipVertex^);
  249.        end else begin
  250.         ClipVertices[1].Add(Vector3Lerp(FirstClipVertex^,EndClipVertex^,StartDistance/(StartDistance-EndDistance)));
  251.        end;
  252.       end else if EndDistance<0.0 then begin
  253.        ClipVertices[1].Add(Vector3Lerp(FirstClipVertex^,EndClipVertex^,StartDistance/(StartDistance-EndDistance)));
  254.        ClipVertices[1].Add(EndClipVertex^);
  255.       end;
  256.       FirstClipVertex:=EndClipVertex;
  257.       StartDistance:=EndDistance;
  258.      end;
  259.     end;
  260.     if ClipVertices[1].Count=0 then begin
  261.      exit;
  262.     end else begin
  263.      ClipVertices[2]:=ClipVertices[0];
  264.      ClipVertices[0]:=ClipVertices[1];
  265.      ClipVertices[1]:=ClipVertices[2];
  266.      ClipVertices[1].Clear;
  267.      OtherReferenceVertexIndex:=ReferenceVertexIndex;
  268.     end;
  269.    end;
  270.  
  271.    for ClipVertexIndex:=0 to ClipVertices[0].Count-1 do begin
  272.     ClipVertex:=@ClipVertices[0].Vertices[ClipVertexIndex];
  273.     Distance:=PlaneVectorDistance(ReferenceWorldPlane,ClipVertex^);
  274.     if Distance<0.0 then begin
  275.      if ContactManager.CountTemporaryContacts[ThreadIndex]<MAX_TEMPORARY_CONTACTS then begin
  276.       Contact:=@ContactManager.TemporaryContacts[ThreadIndex,ContactManager.CountTemporaryContacts[ThreadIndex]];
  277.       inc(ContactManager.CountTemporaryContacts[ThreadIndex]);
  278.       Contact^.WorldPositions[0]:=ClipVertex^;
  279.       Contact^.WorldPositions[1]:=ClipVertex^;
  280.       Contact^.LocalPositions[0]:=Vector3TermMatrixMul(ClipVertex^,ShapeA.InverseWorldTransform);
  281.       Contact^.LocalPositions[1]:=Vector3TermMatrixMul(ClipVertex^,ShapeB.InverseWorldTransform);
  282.       Contact^.Penetration:=Distance;
  283.       Contact^.FeaturePair.Key:=$ffffffff; // $ffffffff => nearest current-frame=>last-frame contact point search for warm starting
  284.      end else begin
  285.       break;
  286.      end;
  287.     end;
  288.    end;
  289.  
  290.   end;
  291.  var Contact:PEnginePhysicsContact;
  292.      Iteration,ReferenceFaceIndex,IncidentFaceIndex:longint;
  293.      EdgeA,EdgeB:PEnginePhysicsConvexHullEdge;
  294.      PenetrationDepth:single;
  295.      pa,pb,Normal:TVector3;
  296.      ConvexShapes:array[0..1] of TEnginePhysicsConvexShape;
  297.  begin
  298.  
  299.   Manifold.Persistent:=false;
  300.   Manifold.CountContacts:=0;
  301.  
  302.   Iteration:=0;
  303.   while Iteration<2 do begin
  304.  
  305.    ContactManager.CountTemporaryContacts[ThreadIndex]:=0;
  306.  
  307.    if Iteration=0 then begin
  308.  
  309.     if Manifold.HaveData then begin
  310.  
  311.      if (Manifold.FaceQueryAB.Index>=0) and (Manifold.FaceQueryAB.Separation>0.0) then begin
  312.       if TestEarlyFaceDirection(ShapeA,ShapeB,Manifold.FaceQueryAB) then begin
  313.        // Still existent seperating axis from last frame found, so exit!
  314.        exit;
  315.       end else begin
  316.        // Reject the try to rebuild the contact manifold from last frame, and process a new full seperating axis test
  317.        Iteration:=1;
  318.        continue;
  319.       end;
  320.      end else if (Manifold.FaceQueryBA.Index>=0) and (Manifold.FaceQueryBA.Separation>0.0) then begin
  321.       if TestEarlyFaceDirection(ShapeB,ShapeA,Manifold.FaceQueryBA) then begin
  322.        // Still existent seperating axis from last frame found, so exit!
  323.        exit;
  324.       end else begin
  325.        // Reject the try to rebuild the contact manifold from last frame, and process a new full seperating axis test
  326.        Iteration:=1;
  327.        continue;
  328.       end;
  329.      end else if ((Manifold.EdgeQuery.IndexA>=0) and (Manifold.EdgeQuery.IndexB>=0)) and (Manifold.EdgeQuery.Separation>0.0) then begin
  330.       if TestEarlyEdgeDirection(ShapeA,ShapeB,Manifold.EdgeQuery) then begin
  331.        // Still existent seperating axis from last frame found, so exit!
  332.        exit;
  333.       end else begin
  334.        // Reject the try to rebuild the contact manifold from last frame, and process a new full seperating axis test
  335.        Iteration:=1;
  336.        continue;
  337.       end;
  338.      end else if ((Manifold.FaceQueryAB.Index<0) or (Manifold.FaceQueryAB.Separation>0.0)) or
  339.                  ((Manifold.FaceQueryBA.Index<0) or (Manifold.FaceQueryBA.Separation>0.0)) or
  340.                  (((Manifold.EdgeQuery.IndexA<0) or (Manifold.EdgeQuery.IndexB<0)) or (Manifold.EdgeQuery.Separation>0.0)) then begin
  341.       // Reject the try to rebuild the contact manifold from last frame, and process a new full seperating axis test
  342.       Iteration:=1;
  343.       continue;
  344.      end else begin
  345.       if TestEarlyFaceDirection(ShapeA,ShapeB,Manifold.FaceQueryAB) then begin
  346.        // Still existent seperating axis from last frame found, so exit!
  347.        exit;
  348.       end else if TestEarlyFaceDirection(ShapeB,ShapeA,Manifold.FaceQueryBA) then begin
  349.        // Still existent seperating axis from last frame found, so exit!
  350.        exit;
  351.       end else if TestEarlyEdgeDirection(ShapeA,ShapeB,Manifold.EdgeQuery) then begin
  352.        // Still existent seperating axis from last frame found, so exit!
  353.        exit;
  354.       end else if ((Manifold.EdgeQuery.IndexA>=0) and (Manifold.EdgeQuery.IndexB>=0)) and
  355.                   ((Manifold.EdgeQuery.Separation>(Manifold.FaceQueryAB.Separation+kTolerance)) and (Manifold.EdgeQuery.Separation>(Manifold.FaceQueryBA.Separation+kTolerance))) then begin
  356.        // Reject the try to rebuild the contact manifold from last frame, and process a new full seperating axis test
  357.        Iteration:=1;
  358.        continue;
  359.       end else begin
  360.        // Okay in this case, we can try to rebuild the contact manifold from last frame
  361.       end;
  362.      end;
  363.  
  364.     end else begin
  365.  
  366.      // We must process a full seperating axis test, since there are no last frame contact manifold data yet
  367.      Iteration:=1;
  368.      continue;
  369.  
  370.     end;
  371.  
  372.    end else begin
  373.  
  374.     Manifold.FaceQueryAB.Index:=-1;
  375.     Manifold.FaceQueryAB.Separation:=3.4e+38;
  376.  
  377.     Manifold.FaceQueryBA.Index:=-1;
  378.     Manifold.FaceQueryBA.Separation:=3.4e+38;
  379.  
  380.     Manifold.EdgeQuery.IndexA:=-1;
  381.     Manifold.EdgeQuery.IndexB:=-1;
  382.     Manifold.EdgeQuery.Separation:=3.4e+38;
  383.  
  384.     Manifold.HaveData:=true;
  385.  
  386.     QueryFaceDirections(ShapeA,ShapeB,Manifold.FaceQueryAB);
  387.     if Manifold.FaceQueryAB.Separation>0.0 then begin
  388.      exit;
  389.     end;
  390.  
  391.     QueryFaceDirections(ShapeB,ShapeA,Manifold.FaceQueryBA);
  392.     if Manifold.FaceQueryBA.Separation>0.0 then begin
  393.      exit;
  394.     end;
  395.  
  396.     QueryEdgeDirections(ShapeA,ShapeB,Manifold.EdgeQuery);
  397.     if Manifold.EdgeQuery.Separation>0.0 then begin
  398.      exit;
  399.     end;
  400.  
  401.    end;
  402.  
  403.    if ((Manifold.EdgeQuery.IndexA>=0) and (Manifold.EdgeQuery.IndexB>=0)) and
  404.       ((Manifold.EdgeQuery.Separation>(Manifold.FaceQueryAB.Separation+kTolerance)) and (Manifold.EdgeQuery.Separation>(Manifold.FaceQueryBA.Separation+kTolerance))) then begin
  405.  
  406.     // Edge contact
  407.  
  408.     Manifold.HaveData:=false;
  409.  
  410.     EdgeA:=@ShapeA.ConvexHull.Edges[Manifold.EdgeQuery.IndexA];
  411.     EdgeB:=@ShapeB.ConvexHull.Edges[Manifold.EdgeQuery.IndexB];
  412.  
  413.     if GetEdgeContact(pa,
  414.                       pb,
  415.                       Normal,
  416.                       Vector3TermMatrixMul(ShapeA.ConvexHull.Vertices[EdgeA^.Vertices[0]].Position,ShapeA.WorldTransform),
  417.                       Vector3TermMatrixMul(ShapeA.ConvexHull.Vertices[EdgeA^.Vertices[1]].Position,ShapeA.WorldTransform),
  418.                       Vector3TermMatrixMul(ShapeB.ConvexHull.Vertices[EdgeB^.Vertices[0]].Position,ShapeB.WorldTransform),
  419.                       Vector3TermMatrixMul(ShapeB.ConvexHull.Vertices[EdgeB^.Vertices[1]].Position,ShapeB.WorldTransform),
  420.                       Vector3Sub(ShapeA.GetCenter(ShapeA.WorldTransform),ShapeB.GetCenter(ShapeB.WorldTransform))) then begin
  421.      PenetrationDepth:=Vector3Dot(Vector3Sub(pb,pa),Normal);
  422.      if PenetrationDepth<0.0 then begin
  423.       Manifold.Normal:=Vector3Neg(Normal);
  424.       Contact:=@ContactManager.TemporaryContacts[ThreadIndex,ContactManager.CountTemporaryContacts[ThreadIndex]];
  425.       inc(ContactManager.CountTemporaryContacts[ThreadIndex]);
  426.       Contact^.WorldPositions[0]:=Vector3Avg(pa,pb);
  427.       Contact^.WorldPositions[1]:=Contact^.WorldPositions[0];
  428.       Contact^.LocalPositions[0]:=Vector3TermMatrixMul(Contact^.WorldPositions[0],ShapeA.InverseWorldTransform);
  429.       Contact^.LocalPositions[1]:=Vector3TermMatrixMul(Contact^.WorldPositions[1],ShapeB.InverseWorldTransform);
  430.       Contact^.Penetration:=PenetrationDepth;
  431.       Contact^.FeaturePair.Key:=$ffffffff; // $ffffffff => nearest current-frame=>last-frame contact point search for warm starting
  432.      end;
  433.     end;
  434.  
  435.     if (Iteration>0) and (ContactManager.CountTemporaryContacts[ThreadIndex]=0) then begin
  436.      // MPR to the rescue! This case should never happen, but secure is secure :-)
  437.      ConvexShapes[0].Data:=ShapeA;
  438.      ConvexShapes[0].Transform:=@ShapeA.WorldTransform;
  439.      ConvexShapes[0].CenterFunction:=@ConvexShapeCenterFunctionShape;
  440.      ConvexShapes[0].SupportFunction:=@ConvexShapeSupportFunctionShape;
  441.      ConvexShapes[1].Data:=ShapeB;
  442.      ConvexShapes[1].Transform:=@ShapeB.WorldTransform;
  443.      ConvexShapes[1].CenterFunction:=@ConvexShapeCenterFunctionShape;
  444.      ConvexShapes[1].SupportFunction:=@ConvexShapeSupportFunctionShape;
  445.      if MPRPenetration(@ConvexShapes[0],@ConvexShapes[1],pa,pb,Normal,PenetrationDepth) then begin
  446.       Manifold.Normal:=Vector3Neg(Normal);
  447.       Contact:=@ContactManager.TemporaryContacts[ThreadIndex,ContactManager.CountTemporaryContacts[ThreadIndex]];
  448.       inc(ContactManager.CountTemporaryContacts[ThreadIndex]);
  449.       Contact^.WorldPositions[0]:=Vector3Avg(pa,pb);
  450.       Contact^.WorldPositions[1]:=Contact^.WorldPositions[0];
  451.       Contact^.LocalPositions[0]:=Vector3TermMatrixMul(Contact^.WorldPositions[0],ShapeA.InverseWorldTransform);
  452.       Contact^.LocalPositions[1]:=Vector3TermMatrixMul(Contact^.WorldPositions[1],ShapeB.InverseWorldTransform);
  453.       Contact^.Penetration:=-PenetrationDepth;
  454.       Contact^.FeaturePair.Key:=$ffffffff; // $ffffffff => nearest current-frame=>last-frame contact point search for warm starting
  455.      end;
  456.     end;
  457.  
  458.    end else begin
  459.  
  460.     // Face contact
  461.  
  462.     // TODO: Is it the (or also a) correct way, that the reference face for
  463.     // clipping in this implementation is always on HullA, and the clipping
  464.     // incident face always on HullB? At least, in this case the contact
  465.     // points are always directly automatically coherence and consistent
  466.     // without plane reprojection (among other things for warm starting for
  467.     // the nearest new->old feature-ID-key-free contact point search between
  468.     // last and current frame). It seems, that Bullet does also in this way.
  469.     // And this way implementation works pretty well so far. At least, I saw
  470.     // no failure cases at my tests so far.
  471.     //
  472.     // The alternative solution should be that a face from HullB could also
  473.     // the clip reference face, where the contact points would be projected
  474.     // to the HullA in-this-case-now incident face then, but will be it the
  475.     // more correct way? It seems, that the most other physics engines
  476.     // (but not Bullet) does in this way, but these uses often contact pair
  477.     // feature ID keys then.
  478.     //
  479.     // Or in other words, what are the pros&cons of the two possible
  480.     // face-face-clipping implementation ways?
  481.  
  482.     if (Manifold.FaceQueryAB.Separation+EPSILON)>Manifold.FaceQueryBA.Separation then begin
  483.  
  484.      ReferenceFaceIndex:=Manifold.FaceQueryAB.Index;
  485.      IncidentFaceIndex:=FindIncidentFaceIndex(ShapeA,Manifold.FaceQueryAB.Index,ShapeB);
  486.  
  487.      Manifold.Normal:=Vector3TermMatrixMulBasis(ShapeA.ConvexHull.Faces[Manifold.FaceQueryAB.Index].Plane.Normal,ShapeA.WorldTransform);
  488.  
  489.     end else begin
  490.  
  491.      ReferenceFaceIndex:=FindIncidentFaceIndex(ShapeB,Manifold.FaceQueryBA.Index,ShapeA);
  492.      IncidentFaceIndex:=Manifold.FaceQueryBA.Index;
  493.  
  494.      // The HullB face normal must be corrected (negated) for a still consistent normal orientation
  495.      Manifold.Normal:=Vector3Neg(Vector3TermMatrixMulBasis(ShapeB.ConvexHull.Faces[Manifold.FaceQueryBA.Index].Plane.Normal,ShapeB.WorldTransform));
  496.  
  497.     end;
  498.     ClipFaceContactPoints(ShapeA,ReferenceFaceIndex,ShapeB,IncidentFaceIndex);
  499.  
  500.    end;
  501.  
  502.    if ContactManager.CountTemporaryContacts[ThreadIndex]>0 then begin
  503.     // Contacts found, reduce these down to four contacts with the largest area
  504.     Manifold.CountContacts:=ContactManager.ReduceContacts(pointer(@ContactManager.TemporaryContacts[ThreadIndex,0]),ContactManager.CountTemporaryContacts[ThreadIndex],pointer(@Manifold.Contacts[0]));
  505.     exit;
  506.    end else begin
  507.     if Iteration=0 then begin
  508.      // We must process a new full seperating axis test, since the last frame contact manifold could not rebuilt.
  509.      inc(Iteration);
  510.     end else begin
  511.      // No contacts found
  512.      exit;
  513.     end;
  514.    end;
  515.  
  516.   end;
  517.  
  518.  end;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement