Path: blob/master/modules/godot_physics_3d/gjk_epa.cpp
10277 views
/**************************************************************************/1/* gjk_epa.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "gjk_epa.h"3132/* Disabling formatting for thirdparty code snippet */33/* clang-format off */3435/*************** Bullet's GJK-EPA2 IMPLEMENTATION *******************/3637/*38Bullet Continuous Collision Detection and Physics Library39Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/4041This software is provided 'as-is', without any express or implied warranty.42In no event will the authors be held liable for any damages arising from the43use of this software.44Permission is granted to anyone to use this software for any purpose,45including commercial applications, and to alter it and redistribute it46freely,47subject to the following restrictions:48491. The origin of this software must not be misrepresented; you must not50claim that you wrote the original software. If you use this software in a51product, an acknowledgment in the product documentation would be appreciated52but is not required.532. Altered source versions must be plainly marked as such, and must not be54misrepresented as being the original software.553. This notice may not be removed or altered from any source distribution.56*/5758/*59GJK-EPA collision solver by Nathanael Presson, 200860*/6162// Config6364/* GJK */65#define GJK_MAX_ITERATIONS 12866#define GJK_ACCURACY ((real_t)0.0001)67#define GJK_MIN_DISTANCE ((real_t)0.0001)68#define GJK_DUPLICATED_EPS ((real_t)0.0001)69#define GJK_SIMPLEX2_EPS ((real_t)0.0)70#define GJK_SIMPLEX3_EPS ((real_t)0.0)71#define GJK_SIMPLEX4_EPS ((real_t)0.0)7273/* EPA */74#define EPA_MAX_VERTICES 12875#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)76#define EPA_MAX_ITERATIONS 25577// -- GODOT start --78//#define EPA_ACCURACY ((real_t)0.0001)79#define EPA_ACCURACY ((real_t)0.00001)80// -- GODOT end --81#define EPA_FALLBACK (10*EPA_ACCURACY)82#define EPA_PLANE_EPS ((real_t)0.00001)83#define EPA_INSIDE_EPS ((real_t)0.01)8485namespace GjkEpa2 {868788struct sResults {89enum eStatus {90Separated, /* Shapes doesn't penetrate */91Penetrating, /* Shapes are penetrating */92GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */93EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */94} status;9596Vector3 witnesses[2];97Vector3 normal;98real_t distance = 0.0;99};100101// Shorthands102typedef unsigned int U;103typedef unsigned char U1;104105// MinkowskiDiff106struct MinkowskiDiff {107const GodotShape3D* m_shapes[2];108109Transform3D transform_A;110Transform3D transform_B;111112real_t margin_A = 0.0;113real_t margin_B = 0.0;114115Vector3 (*get_support)(const GodotShape3D*, const Vector3&, real_t) = nullptr;116117void Initialize(const GodotShape3D* shape0, const Transform3D& wtrs0, const real_t margin0,118const GodotShape3D* shape1, const Transform3D& wtrs1, const real_t margin1) {119m_shapes[0] = shape0;120m_shapes[1] = shape1;121transform_A = wtrs0;122transform_B = wtrs1;123margin_A = margin0;124margin_B = margin1;125126if ((margin0 > 0.0) || (margin1 > 0.0)) {127get_support = get_support_with_margin;128} else {129get_support = get_support_without_margin;130}131}132133static Vector3 get_support_without_margin(const GodotShape3D* p_shape, const Vector3& p_dir, real_t p_margin) {134return p_shape->get_support(p_dir.normalized());135}136137static Vector3 get_support_with_margin(const GodotShape3D* p_shape, const Vector3& p_dir, real_t p_margin) {138Vector3 local_dir_norm = p_dir;139if (local_dir_norm.length_squared() < CMP_EPSILON2) {140local_dir_norm = Vector3(-1.0, -1.0, -1.0);141}142local_dir_norm.normalize();143144return p_shape->get_support(local_dir_norm) + p_margin * local_dir_norm;145}146147// i wonder how this could be sped up... if it can148_FORCE_INLINE_ Vector3 Support0(const Vector3& d) const {149return transform_A.xform(get_support(m_shapes[0], transform_A.basis.xform_inv(d), margin_A));150}151152_FORCE_INLINE_ Vector3 Support1(const Vector3& d) const {153return transform_B.xform(get_support(m_shapes[1], transform_B.basis.xform_inv(d), margin_B));154}155156_FORCE_INLINE_ Vector3 Support (const Vector3& d) const {157return (Support0(d) - Support1(-d));158}159160_FORCE_INLINE_ Vector3 Support(const Vector3& d, U index) const {161if (index) {162return Support1(d);163} else {164return Support0(d);165}166}167};168169typedef MinkowskiDiff tShape;170171172// GJK173struct GJK174{175/* Types */176struct sSV177{178Vector3 d,w;179};180struct sSimplex181{182sSV* c[4];183real_t p[4];184U rank;185};186struct eStatus { enum _ {187Valid,188Inside,189Failed };};190/* Fields */191tShape m_shape;192Vector3 m_ray;193real_t m_distance = 0.0f;194sSimplex m_simplices[2];195sSV m_store[4];196sSV* m_free[4];197U m_nfree = 0;198U m_current = 0;199sSimplex* m_simplex = nullptr;200eStatus::_ m_status;201/* Methods */202GJK()203{204Initialize();205}206void Initialize()207{208m_ray = Vector3(0,0,0);209m_nfree = 0;210m_status = eStatus::Failed;211m_current = 0;212m_distance = 0;213}214eStatus::_ Evaluate(const tShape& shapearg,const Vector3& guess)215{216U iterations=0;217real_t sqdist=0;218real_t alpha=0;219Vector3 lastw[4];220U clastw=0;221/* Initialize solver */222m_free[0] = &m_store[0];223m_free[1] = &m_store[1];224m_free[2] = &m_store[2];225m_free[3] = &m_store[3];226m_nfree = 4;227m_current = 0;228m_status = eStatus::Valid;229m_shape = shapearg;230m_distance = 0;231/* Initialize simplex */232m_simplices[0].rank = 0;233m_ray = guess;234const real_t sqrl= m_ray.length_squared();235appendvertice(m_simplices[0],sqrl>0?-m_ray:Vector3(1,0,0));236m_simplices[0].p[0] = 1;237m_ray = m_simplices[0].c[0]->w;238sqdist = sqrl;239lastw[0] =240lastw[1] =241lastw[2] =242lastw[3] = m_ray;243/* Loop */244do {245const U next=1-m_current;246sSimplex& cs=m_simplices[m_current];247sSimplex& ns=m_simplices[next];248/* Check zero */249const real_t rl=m_ray.length();250if(rl<GJK_MIN_DISTANCE)251{/* Touching or inside */252m_status=eStatus::Inside;253break;254}255/* Append new vertice in -'v' direction */256appendvertice(cs,-m_ray);257const Vector3& w=cs.c[cs.rank-1]->w;258bool found=false;259for(U i=0;i<4;++i)260{261if((w-lastw[i]).length_squared()<GJK_DUPLICATED_EPS)262{ found=true;break; }263}264if(found)265{/* Return old simplex */266removevertice(m_simplices[m_current]);267break;268}269else270{/* Update lastw */271lastw[clastw=(clastw+1)&3]=w;272}273/* Check for termination */274const real_t omega=vec3_dot(m_ray,w)/rl;275alpha=MAX(omega,alpha);276if(((rl-alpha)-(GJK_ACCURACY*rl))<=0)277{/* Return old simplex */278removevertice(m_simplices[m_current]);279break;280}281/* Reduce simplex */282real_t weights[4];283U mask=0;284switch(cs.rank)285{286case 2: sqdist=projectorigin( cs.c[0]->w,287cs.c[1]->w,288weights,mask);break;289case 3: sqdist=projectorigin( cs.c[0]->w,290cs.c[1]->w,291cs.c[2]->w,292weights,mask);break;293case 4: sqdist=projectorigin( cs.c[0]->w,294cs.c[1]->w,295cs.c[2]->w,296cs.c[3]->w,297weights,mask);break;298}299if(sqdist>=0)300{/* Valid */301ns.rank = 0;302m_ray = Vector3(0,0,0);303m_current = next;304for(U i=0,ni=cs.rank;i<ni;++i)305{306if(mask&(1<<i))307{308ns.c[ns.rank] = cs.c[i];309ns.p[ns.rank++] = weights[i];310m_ray += cs.c[i]->w*weights[i];311}312else313{314m_free[m_nfree++] = cs.c[i];315}316}317if(mask==15) { m_status=eStatus::Inside;318}319}320else321{/* Return old simplex */322removevertice(m_simplices[m_current]);323break;324}325m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eStatus::Failed;326} while(m_status==eStatus::Valid);327m_simplex=&m_simplices[m_current];328switch(m_status)329{330case eStatus::Valid: m_distance=m_ray.length();break;331case eStatus::Inside: m_distance=0;break;332default: {}333}334return(m_status);335}336bool EncloseOrigin()337{338switch(m_simplex->rank)339{340case 1:341{342for(U i=0;i<3;++i)343{344Vector3 axis=Vector3(0,0,0);345axis[i]=1;346appendvertice(*m_simplex, axis);347if(EncloseOrigin()) { return(true);348}349removevertice(*m_simplex);350appendvertice(*m_simplex,-axis);351if(EncloseOrigin()) { return(true);352}353removevertice(*m_simplex);354}355}356break;357case 2:358{359const Vector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;360for(U i=0;i<3;++i)361{362Vector3 axis=Vector3(0,0,0);363axis[i]=1;364const Vector3 p=vec3_cross(d,axis);365if(p.length_squared()>0)366{367appendvertice(*m_simplex, p);368if(EncloseOrigin()) { return(true);369}370removevertice(*m_simplex);371appendvertice(*m_simplex,-p);372if(EncloseOrigin()) { return(true);373}374removevertice(*m_simplex);375}376}377}378break;379case 3:380{381const Vector3 n=vec3_cross(m_simplex->c[1]->w-m_simplex->c[0]->w,382m_simplex->c[2]->w-m_simplex->c[0]->w);383if(n.length_squared()>0)384{385appendvertice(*m_simplex,n);386if(EncloseOrigin()) { return(true);387}388removevertice(*m_simplex);389appendvertice(*m_simplex,-n);390if(EncloseOrigin()) { return(true);391}392removevertice(*m_simplex);393}394}395break;396case 4:397{398if(Math::abs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,399m_simplex->c[1]->w-m_simplex->c[3]->w,400m_simplex->c[2]->w-m_simplex->c[3]->w))>0) {401return(true);402}403}404break;405}406return(false);407}408/* Internals */409void getsupport(const Vector3& d,sSV& sv) const410{411sv.d = d/d.length();412sv.w = m_shape.Support(sv.d);413}414void removevertice(sSimplex& simplex)415{416m_free[m_nfree++]=simplex.c[--simplex.rank];417}418void appendvertice(sSimplex& simplex,const Vector3& v)419{420simplex.p[simplex.rank]=0;421simplex.c[simplex.rank]=m_free[--m_nfree];422getsupport(v,*simplex.c[simplex.rank++]);423}424static real_t det(const Vector3& a,const Vector3& b,const Vector3& c)425{426return( a.y*b.z*c.x+a.z*b.x*c.y-427a.x*b.z*c.y-a.y*b.x*c.z+428a.x*b.y*c.z-a.z*b.y*c.x);429}430static real_t projectorigin( const Vector3& a,431const Vector3& b,432real_t* w,U& m)433{434const Vector3 d=b-a;435const real_t l=d.length_squared();436if(l>GJK_SIMPLEX2_EPS)437{438const real_t t(l>0?-vec3_dot(a,d)/l:0);439if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length_squared()); }440else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length_squared()); }441else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length_squared()); }442}443return(-1);444}445static real_t projectorigin( const Vector3& a,446const Vector3& b,447const Vector3& c,448real_t* w,U& m)449{450static const U imd3[]={1,2,0};451const Vector3* vt[]={&a,&b,&c};452const Vector3 dl[]={a-b,b-c,c-a};453const Vector3 n=vec3_cross(dl[0],dl[1]);454const real_t l=n.length_squared();455if(l>GJK_SIMPLEX3_EPS)456{457real_t mindist=-1;458real_t subw[2] = { 0 , 0};459U subm = 0;460for(U i=0;i<3;++i)461{462if(vec3_dot(*vt[i],vec3_cross(dl[i],n))>0)463{464const U j=imd3[i];465const real_t subd(projectorigin(*vt[i],*vt[j],subw,subm));466if((mindist<0)||(subd<mindist))467{468mindist = subd;469m = static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));470w[i] = subw[0];471w[j] = subw[1];472w[imd3[j]] = 0;473}474}475}476if(mindist<0)477{478const real_t d=vec3_dot(a,n);479const real_t s=Math::sqrt(l);480const Vector3 p=n*(d/l);481mindist = p.length_squared();482m = 7;483w[0] = (vec3_cross(dl[1],b-p)).length()/s;484w[1] = (vec3_cross(dl[2],c-p)).length()/s;485w[2] = 1-(w[0]+w[1]);486}487return(mindist);488}489return(-1);490}491static real_t projectorigin( const Vector3& a,492const Vector3& b,493const Vector3& c,494const Vector3& d,495real_t* w,U& m)496{497static const U imd3[]={1,2,0};498const Vector3* vt[]={&a,&b,&c,&d};499const Vector3 dl[]={a-d,b-d,c-d};500const real_t vl=det(dl[0],dl[1],dl[2]);501const bool ng=(vl*vec3_dot(a,vec3_cross(b-c,a-b)))<=0;502if(ng&&(Math::abs(vl)>GJK_SIMPLEX4_EPS))503{504real_t mindist=-1;505real_t subw[3] = {0.f, 0.f, 0.f};506U subm=0;507for(U i=0;i<3;++i)508{509const U j=imd3[i];510const real_t s=vl*vec3_dot(d,vec3_cross(dl[i],dl[j]));511if(s>0)512{513const real_t subd=projectorigin(*vt[i],*vt[j],d,subw,subm);514if((mindist<0)||(subd<mindist))515{516mindist = subd;517m = static_cast<U>((subm&1?1<<i:0)+518(subm&2?1<<j:0)+519(subm&4?8:0));520w[i] = subw[0];521w[j] = subw[1];522w[imd3[j]] = 0;523w[3] = subw[2];524}525}526}527if(mindist<0)528{529mindist = 0;530m = 15;531w[0] = det(c,b,d)/vl;532w[1] = det(a,c,d)/vl;533w[2] = det(b,a,d)/vl;534w[3] = 1-(w[0]+w[1]+w[2]);535}536return(mindist);537}538return(-1);539}540};541542// EPA543struct EPA544{545/* Types */546typedef GJK::sSV sSV;547struct sFace548{549Vector3 n;550real_t d = 0.0f;551sSV* c[3];552sFace* f[3];553sFace* l[2];554U1 e[3];555U1 pass = 0;556};557struct sList558{559sFace* root = nullptr;560U count = 0;561sList() {}562};563struct sHorizon564{565sFace* cf = nullptr;566sFace* ff = nullptr;567U nf = 0;568sHorizon() {}569};570struct eStatus { enum _ {571Valid,572Touching,573Degenerated,574NonConvex,575InvalidHull,576OutOfFaces,577OutOfVertices,578AccuraryReached,579FallBack,580Failed };};581/* Fields */582eStatus::_ m_status;583GJK::sSimplex m_result;584Vector3 m_normal;585real_t m_depth = 0.0f;586sSV m_sv_store[EPA_MAX_VERTICES];587sFace m_fc_store[EPA_MAX_FACES];588U m_nextsv = 0;589sList m_hull;590sList m_stock;591/* Methods */592EPA()593{594Initialize();595}596597598static inline void bind(sFace* fa,U ea,sFace* fb,U eb)599{600fa->e[ea]=(U1)eb;fa->f[ea]=fb;601fb->e[eb]=(U1)ea;fb->f[eb]=fa;602}603static inline void append(sList& list,sFace* face)604{605face->l[0] = nullptr;606face->l[1] = list.root;607if(list.root) { list.root->l[0]=face;608}609list.root = face;610++list.count;611}612static inline void remove(sList& list,sFace* face)613{614if(face->l[1]) { face->l[1]->l[0]=face->l[0];615}616if(face->l[0]) { face->l[0]->l[1]=face->l[1];617}618if(face==list.root) { list.root=face->l[1];619}620--list.count;621}622623624void Initialize()625{626m_status = eStatus::Failed;627m_normal = Vector3(0,0,0);628m_depth = 0;629m_nextsv = 0;630for(U i=0;i<EPA_MAX_FACES;++i)631{632append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);633}634}635eStatus::_ Evaluate(GJK& gjk,const Vector3& guess)636{637GJK::sSimplex& simplex=*gjk.m_simplex;638if((simplex.rank>1)&&gjk.EncloseOrigin())639{640/* Clean up */641while(m_hull.root)642{643sFace* f = m_hull.root;644remove(m_hull,f);645append(m_stock,f);646}647m_status = eStatus::Valid;648m_nextsv = 0;649/* Orient simplex */650if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,651simplex.c[1]->w-simplex.c[3]->w,652simplex.c[2]->w-simplex.c[3]->w)<0)653{654SWAP(simplex.c[0],simplex.c[1]);655SWAP(simplex.p[0],simplex.p[1]);656}657/* Build initial hull */658sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),659newface(simplex.c[1],simplex.c[0],simplex.c[3],true),660newface(simplex.c[2],simplex.c[1],simplex.c[3],true),661newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};662if(m_hull.count==4)663{664sFace* best=findbest();665sFace outer=*best;666U pass=0;667U iterations=0;668bind(tetra[0],0,tetra[1],0);669bind(tetra[0],1,tetra[2],0);670bind(tetra[0],2,tetra[3],0);671bind(tetra[1],1,tetra[3],2);672bind(tetra[1],2,tetra[2],1);673bind(tetra[2],2,tetra[3],1);674m_status=eStatus::Valid;675for(;iterations<EPA_MAX_ITERATIONS;++iterations)676{677if(m_nextsv<EPA_MAX_VERTICES)678{679sHorizon horizon;680sSV* w=&m_sv_store[m_nextsv++];681bool valid=true;682best->pass = (U1)(++pass);683gjk.getsupport(best->n,*w);684const real_t wdist=vec3_dot(best->n,w->w)-best->d;685if(wdist>EPA_ACCURACY)686{687for(U j=0;(j<3)&&valid;++j)688{689valid&=expand( pass,w,690best->f[j],best->e[j],691horizon);692}693if(valid&&(horizon.nf>=3))694{695bind(horizon.cf,1,horizon.ff,2);696remove(m_hull,best);697append(m_stock,best);698best=findbest();699outer=*best;700} else { m_status=eStatus::InvalidHull;break; }701} else { m_status=eStatus::AccuraryReached;break; }702} else { m_status=eStatus::OutOfVertices;break; }703}704const Vector3 projection=outer.n*outer.d;705m_normal = outer.n;706m_depth = outer.d;707m_result.rank = 3;708m_result.c[0] = outer.c[0];709m_result.c[1] = outer.c[1];710m_result.c[2] = outer.c[2];711m_result.p[0] = vec3_cross( outer.c[1]->w-projection,712outer.c[2]->w-projection).length();713m_result.p[1] = vec3_cross( outer.c[2]->w-projection,714outer.c[0]->w-projection).length();715m_result.p[2] = vec3_cross( outer.c[0]->w-projection,716outer.c[1]->w-projection).length();717const real_t sum=m_result.p[0]+m_result.p[1]+m_result.p[2];718m_result.p[0] /= sum;719m_result.p[1] /= sum;720m_result.p[2] /= sum;721return(m_status);722}723}724/* Fallback */725m_status = eStatus::FallBack;726m_normal = -guess;727const real_t nl = m_normal.length();728if (nl > 0) {729m_normal = m_normal/nl;730} else {731m_normal = Vector3(1,0,0);732}733m_depth = 0;734m_result.rank=1;735m_result.c[0]=simplex.c[0];736m_result.p[0]=1;737return(m_status);738}739740bool getedgedist(sFace* face, sSV* a, sSV* b, real_t& dist)741{742const Vector3 ba = b->w - a->w;743const Vector3 n_ab = vec3_cross(ba, face->n); // Outward facing edge normal direction, on triangle plane744const real_t a_dot_nab = vec3_dot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required745746if (a_dot_nab < 0) {747// Outside of edge a->b748const real_t ba_l2 = ba.length_squared();749const real_t a_dot_ba = vec3_dot(a->w, ba);750const real_t b_dot_ba = vec3_dot(b->w, ba);751752if (a_dot_ba > 0) {753// Pick distance vertex a754dist = a->w.length();755} else if (b_dot_ba < 0) {756// Pick distance vertex b757dist = b->w.length();758} else {759// Pick distance to edge a->b760const real_t a_dot_b = vec3_dot(a->w, b->w);761dist = Math::sqrt(MAX((a->w.length_squared() * b->w.length_squared() - a_dot_b * a_dot_b) / ba_l2, 0.0));762}763764return true;765}766767return false;768}769770sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)771{772if (m_stock.root) {773sFace* face=m_stock.root;774remove(m_stock,face);775append(m_hull,face);776face->pass = 0;777face->c[0] = a;778face->c[1] = b;779face->c[2] = c;780face->n = vec3_cross(b->w-a->w,c->w-a->w);781const real_t l=face->n.length();782const bool v=l>EPA_ACCURACY;783if (v) {784if (!(getedgedist(face, a, b, face->d) ||785getedgedist(face, b, c, face->d) ||786getedgedist(face, c, a, face->d))) {787// Origin projects to the interior of the triangle788// Use distance to triangle plane789face->d = vec3_dot(a->w, face->n) / l;790}791face->n /= l;792if (forced||(face->d>=-EPA_PLANE_EPS)) {793return(face);794} else {795m_status=eStatus::NonConvex;796}797} else {798m_status=eStatus::Degenerated;799}800remove(m_hull,face);801append(m_stock,face);802return(nullptr);803}804// -- GODOT start --805//m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces;806m_status=eStatus::OutOfFaces;807// -- GODOT end --808return(nullptr);809}810sFace* findbest()811{812sFace* minf=m_hull.root;813real_t mind=minf->d*minf->d;814for(sFace* f=minf->l[1];f;f=f->l[1])815{816const real_t sqd=f->d*f->d;817if(sqd<mind)818{819minf=f;820mind=sqd;821}822}823return(minf);824}825bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon)826{827static const U i1m3[]={1,2,0};828static const U i2m3[]={2,0,1};829if(f->pass!=pass)830{831const U e1=i1m3[e];832if((vec3_dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)833{834sFace* nf=newface(f->c[e1],f->c[e],w,false);835if(nf)836{837bind(nf,0,f,e);838if(horizon.cf) { bind(horizon.cf,1,nf,2); } else { horizon.ff=nf;839}840horizon.cf=nf;841++horizon.nf;842return(true);843}844}845else846{847const U e2=i2m3[e];848f->pass = (U1)pass;849if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&850expand(pass,w,f->f[e2],f->e[e2],horizon))851{852remove(m_hull,f);853append(m_stock,f);854return(true);855}856}857}858return(false);859}860861};862863//864static void Initialize( const GodotShape3D* shape0, const Transform3D& wtrs0, real_t margin0,865const GodotShape3D* shape1, const Transform3D& wtrs1, real_t margin1,866sResults& results,867tShape& shape)868{869/* Results */870results.witnesses[0] = Vector3(0,0,0);871results.witnesses[1] = Vector3(0,0,0);872results.status = sResults::Separated;873/* Shape */874shape.Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1);875}876877878879//880// Api881//882883//884885//886bool Distance( const GodotShape3D* shape0,887const Transform3D& wtrs0,888real_t margin0,889const GodotShape3D* shape1,890const Transform3D& wtrs1,891real_t margin1,892const Vector3& guess,893sResults& results)894{895tShape shape;896Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);897GJK gjk;898GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);899if(gjk_status==GJK::eStatus::Valid)900{901Vector3 w0=Vector3(0,0,0);902Vector3 w1=Vector3(0,0,0);903for(U i=0;i<gjk.m_simplex->rank;++i)904{905const real_t p=gjk.m_simplex->p[i];906w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;907w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;908}909results.witnesses[0] = w0;910results.witnesses[1] = w1;911results.normal = w0-w1;912results.distance = results.normal.length();913results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;914return(true);915}916else917{918results.status = gjk_status==GJK::eStatus::Inside?919sResults::Penetrating :920sResults::GJK_Failed;921return(false);922}923}924925926//927bool Penetration( const GodotShape3D* shape0,928const Transform3D& wtrs0,929real_t margin0,930const GodotShape3D* shape1,931const Transform3D& wtrs1,932real_t margin1,933const Vector3& guess,934sResults& results935)936{937tShape shape;938Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);939GJK gjk;940GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);941switch(gjk_status)942{943case GJK::eStatus::Inside:944{945EPA epa;946EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess);947if(epa_status!=EPA::eStatus::Failed)948{949Vector3 w0=Vector3(0,0,0);950for(U i=0;i<epa.m_result.rank;++i)951{952w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];953}954results.status = sResults::Penetrating;955results.witnesses[0] = w0;956results.witnesses[1] = w0-epa.m_normal*epa.m_depth;957results.normal = -epa.m_normal;958results.distance = -epa.m_depth;959return(true);960} else { results.status=sResults::EPA_Failed;961}962}963break;964case GJK::eStatus::Failed:965results.status=sResults::GJK_Failed;966break;967default: {}968}969return(false);970}971972973974/* Symbols cleanup */975976#undef GJK_MAX_ITERATIONS977#undef GJK_ACCURARY978#undef GJK_MIN_DISTANCE979#undef GJK_DUPLICATED_EPS980#undef GJK_SIMPLEX2_EPS981#undef GJK_SIMPLEX3_EPS982#undef GJK_SIMPLEX4_EPS983984#undef EPA_MAX_VERTICES985#undef EPA_MAX_FACES986#undef EPA_MAX_ITERATIONS987#undef EPA_ACCURACY988#undef EPA_FALLBACK989#undef EPA_PLANE_EPS990#undef EPA_INSIDE_EPS991} // end of namespace992993/* clang-format on */994995bool gjk_epa_calculate_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) {996GjkEpa2::sResults res;997998if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) {999r_result_A = res.witnesses[0];1000r_result_B = res.witnesses[1];1001return true;1002}10031004return false;1005}10061007bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, GodotCollisionSolver3D::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {1008GjkEpa2::sResults res;10091010if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {1011if (p_result_callback) {1012if (p_swap) {1013Vector3 normal = (res.witnesses[1] - res.witnesses[0]).normalized();1014p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, normal, p_userdata);1015} else {1016Vector3 normal = (res.witnesses[0] - res.witnesses[1]).normalized();1017p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, normal, p_userdata);1018}1019}1020return true;1021}10221023return false;1024}102510261027