Here is an example (see image) :-
- The 2 reddish rectangles are static objects (i.e. it can't move).
- The bluish ball is dynamic object.
So far, I manage to get all penetrating information. Let's consider it as our input:-
- To resolve the penetration between
A
and the ball, I may move the ball by eitherVec3(1,0,0)
ORVec3(0,2,0)
. - To resolve the penetration between
B
and the ball, I may move the ball byVec3(0,1,0)
.
^ I store it as a 2D Vec3 array problem = {{Vec3{1,0,0},Vec3{0,2,0}},{Vec3{0,1,0}}}
.
How to find the best movement (minimum size) of Physics object (e.g. ball in the example) to minimize as much penetration as possible?
The best solution in this example is "move ball by Vec3(1,1,0)
: size=1.414".
In real case, the situation can be more complex and ugly,
e.g. it is possible that both A&B (and other Physics object) try to push the ball in a near-opposite direction. (below images)
^ In some scenes, the 2D array problem
may lack some detail, but for simplicity, let's pretend that it explains all information accurately.
C++ Code
Here is my MCVE (coliru) :-
#include<iostream>
#include <utility>
#include <vector>
#include <array>
#include <math.h>
using Vec3=std::array<float, 3>;
float dotProduct(Vec3 vec1,Vec3 vec2){
return vec1[0]*vec2[0]+vec1[1]*vec2[1]+vec1[2]*vec2[2];
}
float size2(Vec3 vec1){
return vec1[0]*vec1[0]+vec1[1]*vec1[1]+vec1[2]*vec1[2];
}
Vec3 mulFloat(Vec3 vec1,float m){
return Vec3{vec1[0]*m,vec1[1]*m,vec1[2]*m};
}
Vec3 normalize(Vec3 vec1){
return mulFloat(vec1,1/sqrt(size2(vec1)));
}
Here is the main()
:-
int main() {
std::vector<std::vector<Vec3>> problem;
std::vector<Vec3> location1;
location1.push_back(Vec3{0,2,0});
location1.push_back(Vec3{1,0,0});
problem.push_back(location1);
std::vector<Vec3> location2;
location2.push_back(Vec3{0,1,0});
problem.push_back(location2);
//^ INPUT
//----- insert YOUR ALGORITHM here ------
Vec3 solution=Vec3{0,2,0};
float totalResidual=0;
for(auto& location : problem){
float residualRemainMin=1000000;//numerical limit
for(auto& orgResidual : location){
Vec3 orgResidualNormalize=normalize(orgResidual);
float orgResidualSize=sqrt(size2(orgResidual));
float residualModifyBy=-dotProduct(orgResidualNormalize,solution);//#1
//"residualModifyBy" is usually negative
float remainResidual=std::max(0.0f,orgResidualSize+residualModifyBy);
//^ "max" because it has no advantage to reduce residual to < 0
residualRemainMin=std::min(residualRemainMin,remainResidual);
//^ "min" because the "OR" word
}
totalResidual+=residualRemainMin;
}
std::cout<<"totalResidual="<<totalResidual;
return 0;
}
Note (#1)
in code: residual is reduced by dotProduct(solution,normalize(orgResidual) )
.
My derivation of this formula comes from this image :-
Side Note
I feel that it would be too slow to permute every combination (which I am not exactly sure how to).
I also believe general iterative approach is too slow to converge.
I just want some guideline ; I don't mind a description-only without-code answer.
Edit (29 June 2019)
More test cases :-
{{(0,3,0)},{(2,2,0)}} ===> (1,3,0)
{{(0,1,1),(10,0,0)},{(0,2,3)}} ===> (0,2,3)
{{(99,1,0),(99,-1,0),(100,0,0)}} ===> (99,1,0) OR (99,-1,0) (equally good)